Set TRIO_LIBS when building with trio.
[platform/upstream/glib.git] / glib / giowin32.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * giowin32.c: IO Channels for Win32.
5  * Copyright 1998 Owen Taylor and Tor Lillqvist
6  * Copyright 1999-2000 Tor Lillqvist and Craig Setera
7  * Copyright 2001 Andrew Lanoix
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 /*
26  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
27  * file for a list of people on the GLib Team.  See the ChangeLog
28  * files for a list of changes.  These files are distributed with
29  * GLib at ftp://ftp.gtk.org/pub/gtk/.
30  */
31
32 /* Define this to get (very) verbose logging of all channels */
33 /* #define G_IO_WIN32_DEBUG */
34
35 #include "config.h"
36
37 #include "glib.h"
38
39 #include <stdlib.h>
40 #include <windows.h>
41 #include <winsock.h>          /* Not everybody has winsock2 */
42 #include <fcntl.h>
43 #include <io.h>
44 #include <process.h>
45 #include <errno.h>
46 #include <sys/stat.h>
47
48 #include "glibintl.h"
49
50 typedef struct _GIOWin32Channel GIOWin32Channel;
51 typedef struct _GIOWin32Watch GIOWin32Watch;
52
53 #define BUFFER_SIZE 4096
54
55 typedef enum {
56   G_IO_WIN32_WINDOWS_MESSAGES,  /* Windows messages */
57   G_IO_WIN32_FILE_DESC,         /* Unix-like file descriptors from
58                                  * _open() or _pipe(). Read with read().
59                                  * Have to create separate thread to read.
60                                  */
61   G_IO_WIN32_SOCKET             /* Sockets. A separate thread is blocked
62                                  * in select() most of the time.
63                                  */
64 } GIOWin32ChannelType;
65
66 struct _GIOWin32Channel {
67   GIOChannel channel;
68   gint fd;                      /* Either a Unix-like file handle as provided
69                                  * by the Microsoft C runtime, or a SOCKET
70                                  * as provided by WinSock.
71                                  */
72   GIOWin32ChannelType type;
73   
74   gboolean debug;
75
76   CRITICAL_SECTION mutex;
77
78   /* This is used by G_IO_WIN32_WINDOWS_MESSAGES channels */
79   HWND hwnd;                    /* handle of window, or NULL */
80   
81   /* Following fields are used by both fd and socket channels. */
82   gboolean running;             /* Is reader thread running. FALSE if
83                                  * EOF has been reached.
84                                  */
85   gboolean needs_close;         /* If the channel has been closed while
86                                  * the reader thread was still running.
87                                  */
88   guint thread_id;              /* If non-NULL has a reader thread, or has
89                                  * had.*/
90   HANDLE thread_handle;
91   HANDLE data_avail_event;
92
93   gushort revents;
94
95   /* Following fields used by fd channels for input */
96   
97   /* Data is kept in a circular buffer. To be able to distinguish between
98    * empty and full buffer, we cannot fill it completely, but have to
99    * leave a one character gap.
100    *
101    * Data available is between indexes rdp and wrp-1 (modulo BUFFER_SIZE).
102    *
103    * Empty:    wrp == rdp
104    * Full:     (wrp + 1) % BUFFER_SIZE == rdp
105    * Partial:  otherwise
106    */
107   guchar *buffer;               /* (Circular) buffer */
108   gint wrp, rdp;                /* Buffer indices for writing and reading */
109   HANDLE space_avail_event;
110
111   /* Following fields used by socket channels */
112   GSList *watches;
113   HANDLE data_avail_noticed_event;
114 };
115
116 #define LOCK(mutex) EnterCriticalSection (&mutex)
117 #define UNLOCK(mutex) LeaveCriticalSection (&mutex)
118
119 struct _GIOWin32Watch {
120   GSource       source;
121   GPollFD       pollfd;
122   GIOChannel   *channel;
123   GIOCondition  condition;
124 };
125
126 static void
127 g_win32_print_access_mode (int flags)
128 {
129   g_print ("%s%s%s%s%s%s%s%s%s%s",
130            ((flags & 0x3) == _O_RDWR ? "O_RDWR" :
131             ((flags & 0x3) == _O_RDONLY ? "O_RDONLY" :
132              ((flags & 0x3) == _O_WRONLY ? "O_WRONLY" : "0"))),
133            (flags & _O_APPEND ? "|O_APPEND" : ""),
134            (flags & _O_RANDOM ? "|O_RANDOM" : ""),
135            (flags & _O_SEQUENTIAL ? "|O_SEQUENTIAL" : ""),
136            (flags & _O_TEMPORARY ? "|O_TEMPORARY" : ""),
137            (flags & _O_CREAT ? "|O_CREAT" : ""),
138            (flags & _O_TRUNC ? "|O_TRUNC" : ""),
139            (flags & _O_EXCL ? "|O_EXCL" : ""),
140            (flags & _O_TEXT ? "|O_TEXT" : ""),
141            (flags & _O_BINARY ? "|O_BINARY" : ""));
142 }
143
144 static void
145 g_win32_print_gioflags (GIOFlags flags)
146 {
147   char *bar = "";
148
149   if (flags & G_IO_FLAG_APPEND)
150     bar = "|", g_print ("APPEND");
151   if (flags & G_IO_FLAG_NONBLOCK)
152     g_print ("%sNONBLOCK", bar), bar = "|";
153   if (flags & G_IO_FLAG_IS_READABLE)
154     g_print ("%sREADABLE", bar), bar = "|";
155   if (flags & G_IO_FLAG_IS_WRITEABLE)
156     g_print ("%sWRITEABLE", bar), bar = "|";
157   if (flags & G_IO_FLAG_IS_WRITEABLE)
158     g_print ("%sWRITEABLE", bar), bar = "|";
159   if (flags & G_IO_FLAG_IS_SEEKABLE)
160     g_print ("%sSEEKABLE", bar), bar = "|";
161 }
162
163 static gboolean
164 g_io_win32_get_debug_flag (void)
165 {
166 #ifdef G_IO_WIN32_DEBUG
167   return TRUE;
168 #else
169   if (getenv ("G_IO_WIN32_DEBUG") != NULL)
170     return TRUE;
171   else
172     return FALSE;
173 #endif
174 }  
175
176 static void
177 g_io_channel_win32_init (GIOWin32Channel *channel)
178 {
179   channel->debug = g_io_win32_get_debug_flag ();
180   channel->buffer = NULL;
181   channel->running = FALSE;
182   channel->needs_close = FALSE;
183   channel->thread_id = 0;
184   channel->data_avail_event = NULL;
185   channel->revents = 0;
186   channel->space_avail_event = NULL;
187   channel->data_avail_noticed_event = NULL;
188   channel->watches = NULL;
189   InitializeCriticalSection (&channel->mutex);
190 }
191
192 static void
193 create_events (GIOWin32Channel *channel)
194 {
195   SECURITY_ATTRIBUTES sec_attrs;
196   
197   sec_attrs.nLength = sizeof (SECURITY_ATTRIBUTES);
198   sec_attrs.lpSecurityDescriptor = NULL;
199   sec_attrs.bInheritHandle = FALSE;
200
201   /* The data available event is manual reset, the space available event
202    * is automatic reset.
203    */
204   if (!(channel->data_avail_event = CreateEvent (&sec_attrs, TRUE, FALSE, NULL))
205       || !(channel->space_avail_event = CreateEvent (&sec_attrs, FALSE, FALSE, NULL))
206       || !(channel->data_avail_noticed_event = CreateEvent (&sec_attrs, FALSE, FALSE, NULL)))
207     {
208       gchar *emsg = g_win32_error_message (GetLastError ());
209       g_error ("Error creating event: %s", emsg);
210       g_free (emsg);
211     }
212 }
213
214 static unsigned __stdcall
215 read_thread (void *parameter)
216 {
217   GIOWin32Channel *channel = parameter;
218   guchar *buffer;
219   guint nbytes;
220
221   g_io_channel_ref ((GIOChannel *)channel);
222
223   if (channel->debug)
224     g_print ("read_thread %#x: start fd:%d, data_avail:%#x space_avail:%#x\n",
225              channel->thread_id,
226              channel->fd,
227              (guint) channel->data_avail_event,
228              (guint) channel->space_avail_event);
229   
230   channel->buffer = g_malloc (BUFFER_SIZE);
231   channel->rdp = channel->wrp = 0;
232   channel->running = TRUE;
233
234   SetEvent (channel->space_avail_event);
235   
236   while (channel->running)
237     {
238       LOCK (channel->mutex);
239       if (channel->debug)
240         g_print ("read_thread %#x: rdp=%d, wrp=%d\n",
241                  channel->thread_id, channel->rdp, channel->wrp);
242       if ((channel->wrp + 1) % BUFFER_SIZE == channel->rdp)
243         {
244           /* Buffer is full */
245           if (channel->debug)
246             g_print ("read_thread %#x: resetting space_avail\n",
247                      channel->thread_id);
248           ResetEvent (channel->space_avail_event);
249           if (channel->debug)
250             g_print ("read_thread %#x: waiting for space\n",
251                      channel->thread_id);
252           UNLOCK (channel->mutex);
253           WaitForSingleObject (channel->space_avail_event, INFINITE);
254           LOCK (channel->mutex);
255           if (channel->debug)
256             g_print ("read_thread %#x: rdp=%d, wrp=%d\n",
257                      channel->thread_id, channel->rdp, channel->wrp);
258         }
259       
260       buffer = channel->buffer + channel->wrp;
261       
262       /* Always leave at least one byte unused gap to be able to
263        * distinguish between the full and empty condition...
264        */
265       nbytes = MIN ((channel->rdp + BUFFER_SIZE - channel->wrp - 1) % BUFFER_SIZE,
266                     BUFFER_SIZE - channel->wrp);
267
268       if (channel->debug)
269         g_print ("read_thread %#x: calling read() for %d bytes\n",
270                  channel->thread_id, nbytes);
271
272       UNLOCK (channel->mutex);
273
274       nbytes = read (channel->fd, buffer, nbytes);
275       
276       LOCK (channel->mutex);
277
278       channel->revents = G_IO_IN;
279       if (nbytes == 0)
280         channel->revents |= G_IO_HUP;
281       else if (nbytes < 0)
282         channel->revents |= G_IO_ERR;
283
284       if (channel->debug)
285         g_print ("read_thread %#x: read() returned %d, rdp=%d, wrp=%d\n",
286                  channel->thread_id, nbytes, channel->rdp, channel->wrp);
287
288       if (nbytes <= 0)
289         break;
290
291       channel->wrp = (channel->wrp + nbytes) % BUFFER_SIZE;
292       if (channel->debug)
293         g_print ("read_thread %#x: rdp=%d, wrp=%d, setting data_avail\n",
294                  channel->thread_id, channel->rdp, channel->wrp);
295       SetEvent (channel->data_avail_event);
296       UNLOCK (channel->mutex);
297     }
298   
299   channel->running = FALSE;
300   if (channel->needs_close)
301     {
302       if (channel->debug)
303         g_print ("read_thread %#x: channel fd %d needs closing\n",
304                  channel->thread_id, channel->fd);
305       close (channel->fd);
306       channel->fd = -1;
307     }
308
309   if (channel->debug)
310     g_print ("read_thread %#x: EOF, rdp=%d, wrp=%d, setting data_avail\n",
311              channel->thread_id, channel->rdp, channel->wrp);
312   SetEvent (channel->data_avail_event);
313   UNLOCK (channel->mutex);
314   
315   g_io_channel_unref((GIOChannel *)channel);
316   
317   /* No need to call _endthreadex(), the actual thread starter routine
318    * in MSVCRT (see crt/src/threadex.c:_threadstartex) calls
319    * _endthreadex() for us.
320    */
321
322   CloseHandle (channel->thread_handle);
323
324   return 0;
325 }
326
327 static void
328 create_thread (GIOWin32Channel     *channel,
329                GIOCondition         condition,
330                unsigned (__stdcall *thread) (void *parameter))
331 {
332   channel->thread_handle =
333     (HANDLE) _beginthreadex (NULL, 0, thread, channel, 0,
334                              &channel->thread_id);
335   if (channel->thread_handle == 0)
336     g_warning (G_STRLOC ": Error creating reader thread: %s",
337                g_strerror (errno));
338   WaitForSingleObject (channel->space_avail_event, INFINITE);
339 }
340
341 static GIOStatus
342 buffer_read (GIOWin32Channel *channel,
343              guchar          *dest,
344              gsize            count,
345              gsize           *bytes_read,
346              GError         **err)
347 {
348   guint nbytes;
349   guint left = count;
350   
351   LOCK (channel->mutex);
352   if (channel->debug)
353     g_print ("reading from thread %#x %d bytes, rdp=%d, wrp=%d\n",
354              channel->thread_id, count, channel->rdp, channel->wrp);
355   
356   if (channel->wrp == channel->rdp)
357     {
358       UNLOCK (channel->mutex);
359       if (channel->debug)
360         g_print ("waiting for data from thread %#x\n", channel->thread_id);
361       WaitForSingleObject (channel->data_avail_event, INFINITE);
362       if (channel->debug)
363         g_print ("done waiting for data from thread %#x\n", channel->thread_id);
364       LOCK (channel->mutex);
365       if (channel->wrp == channel->rdp && !channel->running)
366         {
367           if (channel->debug)
368             g_print ("wrp==rdp, !running\n");
369           UNLOCK (channel->mutex);
370           *bytes_read = 0;
371           return G_IO_STATUS_EOF;
372         }
373     }
374   
375   if (channel->rdp < channel->wrp)
376     nbytes = channel->wrp - channel->rdp;
377   else
378     nbytes = BUFFER_SIZE - channel->rdp;
379   UNLOCK (channel->mutex);
380   nbytes = MIN (left, nbytes);
381   if (channel->debug)
382     g_print ("moving %d bytes from thread %#x\n",
383              nbytes, channel->thread_id);
384   memcpy (dest, channel->buffer + channel->rdp, nbytes);
385   dest += nbytes;
386   left -= nbytes;
387   LOCK (channel->mutex);
388   channel->rdp = (channel->rdp + nbytes) % BUFFER_SIZE;
389   if (channel->debug)
390     g_print ("setting space_avail for thread %#x\n", channel->thread_id);
391   SetEvent (channel->space_avail_event);
392   if (channel->debug)
393     g_print ("for thread %#x: rdp=%d, wrp=%d\n",
394              channel->thread_id, channel->rdp, channel->wrp);
395   if (channel->running && channel->wrp == channel->rdp)
396     {
397       if (channel->debug)
398         g_print ("resetting data_avail of thread %#x\n",
399                  channel->thread_id);
400       ResetEvent (channel->data_avail_event);
401     };
402   UNLOCK (channel->mutex);
403   
404   /* We have no way to indicate any errors form the actual
405    * read() or recv() call in the reader thread. Should we have?
406    */
407   *bytes_read = count - left;
408   return (*bytes_read > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
409 }
410
411 static unsigned __stdcall
412 select_thread (void *parameter)
413 {
414   GIOWin32Channel *channel = parameter;
415   fd_set read_fds, write_fds, except_fds;
416   GSList *tmp;
417   int n;
418
419   g_io_channel_ref ((GIOChannel *)channel);
420
421   if (channel->debug)
422     g_print ("select_thread %#x: start fd:%d data_avail:%#x data_avail_noticed:%#x\n",
423              channel->thread_id,
424              channel->fd,
425              (guint) channel->data_avail_event,
426              (guint) channel->data_avail_noticed_event);
427   
428   channel->rdp = channel->wrp = 0;
429   channel->running = TRUE;
430
431   SetEvent (channel->space_avail_event);
432   
433   while (channel->running)
434     {
435       FD_ZERO (&read_fds);
436       FD_ZERO (&write_fds);
437       FD_ZERO (&except_fds);
438
439       tmp = channel->watches;
440       while (tmp)
441         {
442           GIOWin32Watch *watch = (GIOWin32Watch *)tmp->data;
443
444           if (watch->condition & (G_IO_IN | G_IO_HUP))
445             FD_SET (channel->fd, &read_fds);
446           if (watch->condition & G_IO_OUT)
447             FD_SET (channel->fd, &write_fds);
448           if (watch->condition & G_IO_ERR)
449             FD_SET (channel->fd, &except_fds);
450           
451           tmp = tmp->next;
452         }
453       if (channel->debug)
454         g_print ("select_thread %#x: calling select() for%s%s%s\n",
455                  channel->thread_id,
456                  (FD_ISSET (channel->fd, &read_fds) ? " IN" : ""),
457                  (FD_ISSET (channel->fd, &write_fds) ? " OUT" : ""),
458                  (FD_ISSET (channel->fd, &except_fds) ? " ERR" : ""));
459
460       n = select (1, &read_fds, &write_fds, &except_fds, NULL);
461       
462       if (n == SOCKET_ERROR)
463         {
464           if (channel->debug)
465             g_print ("select_thread %#x: select returned SOCKET_ERROR\n",
466                      channel->thread_id);
467           break;
468         }
469
470       if (channel->debug)
471         g_print ("select_thread %#x: got%s%s%s\n",
472                  channel->thread_id,
473                  (FD_ISSET (channel->fd, &read_fds) ? " IN" : ""),
474                  (FD_ISSET (channel->fd, &write_fds) ? " OUT" : ""),
475                  (FD_ISSET (channel->fd, &except_fds) ? " ERR" : ""));
476
477       if (FD_ISSET (channel->fd, &read_fds))
478         channel->revents |= G_IO_IN;
479       if (FD_ISSET (channel->fd, &write_fds))
480         channel->revents |= G_IO_OUT;
481       if (FD_ISSET (channel->fd, &except_fds))
482         channel->revents |= G_IO_ERR;
483
484       if (channel->debug)
485         g_print ("select_thread %#x: resetting data_avail_noticed, setting data_avail\n",
486                  channel->thread_id);
487       ResetEvent (channel->data_avail_noticed_event);
488       SetEvent (channel->data_avail_event);
489
490       LOCK (channel->mutex);
491       if (channel->needs_close)
492         {
493           UNLOCK (channel->mutex);
494           break;
495         }
496       UNLOCK (channel->mutex);
497
498       if (channel->debug)
499         g_print ("select_thread %#x: waiting for data_avail_noticed\n",
500                  channel->thread_id);
501
502       WaitForSingleObject (channel->data_avail_noticed_event, INFINITE);
503       if (channel->debug)
504         g_print ("select_thread %#x: got data_avail_noticed\n",
505                  channel->thread_id);
506     }
507   
508   channel->running = FALSE;
509   LOCK (channel->mutex);
510   if (channel->fd != -1)
511     {
512       /* DO NOT close the fd here */
513       channel->fd = -1;
514     }
515
516   if (channel->debug)
517     g_print ("select_thread %#x: got error, setting data_avail\n",
518              channel->thread_id);
519   SetEvent (channel->data_avail_event);
520   UNLOCK (channel->mutex);
521   
522   g_io_channel_unref((GIOChannel *)channel);
523   
524   /* No need to call _endthreadex(), the actual thread starter routine
525    * in MSVCRT (see crt/src/threadex.c:_threadstartex) calls
526    * _endthreadex() for us.
527    */
528
529   CloseHandle (channel->thread_handle);
530
531   return 0;
532 }
533
534 static gboolean
535 g_io_win32_prepare (GSource *source,
536                     gint    *timeout)
537 {
538   GIOWin32Watch *watch = (GIOWin32Watch *)source;
539   GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
540   GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
541   
542   *timeout = -1;
543   
544   if (channel->debug)
545     g_print ("g_io_win32_prepare: for thread %#x buffer_condition:%#x\n"
546              "  watch->pollfd.events:%#x watch->pollfd.revents:%#x channel->revents:%#x\n",
547              channel->thread_id, buffer_condition,
548              watch->pollfd.events, watch->pollfd.revents, channel->revents);
549
550   if (channel->type == G_IO_WIN32_FILE_DESC)
551     {
552       LOCK (channel->mutex);
553       if (channel->running && channel->wrp == channel->rdp)
554         {
555           if (channel->debug)
556             g_print ("g_io_win32_prepare: for thread %#x, setting channel->revents = 0\n",
557                      channel->thread_id);
558           channel->revents = 0;
559         }
560       UNLOCK (channel->mutex);
561     }
562   else if (channel->type == G_IO_WIN32_SOCKET)
563     {
564       channel->revents = 0;
565
566       if (channel->debug)
567         g_print ("g_io_win32_prepare: for thread %#x, setting data_avail_noticed\n",
568                  channel->thread_id);
569       SetEvent (channel->data_avail_noticed_event);
570       if (channel->debug)
571         g_print ("g_io_win32_prepare: thread %#x, there.\n",
572                  channel->thread_id);
573     }
574
575   return ((watch->condition & buffer_condition) == watch->condition);
576 }
577
578 static gboolean
579 g_io_win32_check (GSource *source)
580 {
581   MSG msg;
582   GIOWin32Watch *watch = (GIOWin32Watch *)source;
583   GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
584   GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
585
586   if (channel->debug)
587     g_print ("g_io_win32_check: for thread %#x buffer_condition:%#x\n"
588              "  watch->pollfd.events:%#x watch->pollfd.revents:%#x channel->revents:%#x\n",
589              channel->thread_id, buffer_condition,
590              watch->pollfd.events, watch->pollfd.revents, channel->revents);
591
592   if (channel->type != G_IO_WIN32_WINDOWS_MESSAGES)
593     {
594       watch->pollfd.revents = (watch->pollfd.events & channel->revents);
595     }
596   else
597     {
598       return (PeekMessage (&msg, channel->hwnd, 0, 0, PM_NOREMOVE));
599     }
600   
601   if (channel->type == G_IO_WIN32_SOCKET)
602     {
603       if (channel->debug)
604         g_print ("g_io_win32_check: thread %#x, resetting data_avail\n",
605                  channel->thread_id);
606       ResetEvent (channel->data_avail_event);
607       if (channel->debug)
608         g_print ("g_io_win32_check: thread %#x, there.\n",
609                  channel->thread_id);
610     }
611
612   return ((watch->pollfd.revents | buffer_condition) & watch->condition);
613 }
614
615 static gboolean
616 g_io_win32_dispatch (GSource     *source,
617                      GSourceFunc  callback,
618                      gpointer     user_data)
619 {
620   GIOFunc func = (GIOFunc)callback;
621   GIOWin32Watch *watch = (GIOWin32Watch *)source;
622   GIOCondition buffer_condition = g_io_channel_get_buffer_condition (watch->channel);
623   
624   if (!func)
625     {
626       g_warning (G_STRLOC ": GIOWin32Watch dispatched without callback\n"
627                  "You must call g_source_connect().");
628       return FALSE;
629     }
630   
631   return (*func) (watch->channel,
632                   (watch->pollfd.revents | buffer_condition) & watch->condition,
633                   user_data);
634 }
635
636 static void
637 g_io_win32_finalize (GSource *source)
638 {
639   GIOWin32Watch *watch = (GIOWin32Watch *)source;
640   GIOWin32Channel *channel = (GIOWin32Channel *)watch->channel;
641   
642   if (channel->debug)
643     g_print ("g_io_win32_finalize: channel with thread %#x\n",
644              channel->thread_id);
645
646   channel->watches = g_slist_remove (channel->watches, watch);
647
648   SetEvent (channel->data_avail_noticed_event);
649   g_io_channel_unref (watch->channel);
650 }
651
652 #if defined(G_PLATFORM_WIN32) && defined(__GNUC__)
653 __declspec(dllexport)
654 #endif
655 GSourceFuncs g_io_watch_funcs = {
656   g_io_win32_prepare,
657   g_io_win32_check,
658   g_io_win32_dispatch,
659   g_io_win32_finalize
660 };
661
662 static GSource *
663 g_io_win32_create_watch (GIOChannel    *channel,
664                          GIOCondition   condition,
665                          unsigned (__stdcall *thread) (void *parameter))
666 {
667   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
668   GIOWin32Watch *watch;
669   GSource *source;
670
671   source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch));
672   watch = (GIOWin32Watch *)source;
673   
674   watch->channel = channel;
675   g_io_channel_ref (channel);
676   
677   watch->condition = condition;
678   
679   if (win32_channel->data_avail_event == NULL)
680     create_events (win32_channel);
681
682   watch->pollfd.fd = (gint) win32_channel->data_avail_event;
683   watch->pollfd.events = condition;
684   
685   if (win32_channel->debug)
686     g_print ("g_io_win32_create_watch: fd:%d condition:%#x handle:%#x\n",
687              win32_channel->fd, condition, watch->pollfd.fd);
688   
689   win32_channel->watches = g_slist_append (win32_channel->watches, watch);
690
691   if (win32_channel->thread_id == 0)
692     create_thread (win32_channel, condition, thread);
693
694   g_source_add_poll (source, &watch->pollfd);
695   
696   return source;
697 }
698
699 static GIOStatus
700 g_io_win32_msg_read (GIOChannel *channel,
701                      gchar      *buf,
702                      gsize       count,
703                      gsize      *bytes_read,
704                      GError    **err)
705 {
706   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
707   MSG msg;               /* In case of alignment problems */
708   
709   if (count < sizeof (MSG))
710     {
711       g_set_error(err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL,
712         _("Incorrect message size")); /* Informative enough error message? */
713       return G_IO_STATUS_ERROR;
714     }
715   
716   if (win32_channel->debug)
717     g_print ("g_io_win32_msg_read: for %#x\n",
718              (guint) win32_channel->hwnd);
719   if (!PeekMessage (&msg, win32_channel->hwnd, 0, 0, PM_REMOVE))
720     return G_IO_STATUS_AGAIN;
721
722   memmove (buf, &msg, sizeof (MSG));
723   *bytes_read = sizeof (MSG);
724
725   return G_IO_STATUS_NORMAL;
726 }
727
728 static GIOStatus
729 g_io_win32_msg_write (GIOChannel  *channel,
730                       const gchar *buf,
731                       gsize        count,
732                       gsize       *bytes_written,
733                       GError     **err)
734 {
735   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
736   MSG msg;
737   
738   if (count != sizeof (MSG))
739     {
740       g_set_error(err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_INVAL,
741         _("Incorrect message size")); /* Informative enough error message? */
742       return G_IO_STATUS_ERROR;
743     }
744   
745   /* In case of alignment problems */
746   memmove (&msg, buf, sizeof (MSG));
747   if (!PostMessage (win32_channel->hwnd, msg.message, msg.wParam, msg.lParam))
748     {
749       gchar *emsg = g_win32_error_message (GetLastError ());
750       g_set_error(err, G_IO_CHANNEL_ERROR, G_IO_CHANNEL_ERROR_FAILED, emsg);
751       g_free (emsg);
752       return G_IO_STATUS_ERROR;
753     }
754
755   *bytes_written = sizeof (MSG);
756
757   return G_IO_STATUS_NORMAL;
758 }
759
760 static GIOStatus
761 g_io_win32_no_seek (GIOChannel *channel,
762                     glong       offset,
763                     GSeekType   type,
764                     GError     **err)
765 {
766   g_assert_not_reached ();
767
768   return G_IO_STATUS_ERROR;
769 }
770
771 static GIOStatus
772 g_io_win32_msg_close (GIOChannel *channel,
773                       GError    **err)
774 {
775   /* Nothing to be done. Or should we set hwnd to some invalid value? */
776
777   return G_IO_STATUS_NORMAL;
778 }
779
780 static void
781 g_io_win32_free (GIOChannel *channel)
782 {
783   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
784   
785   if (win32_channel->debug)
786     g_print ("thread %#x: freeing channel, fd: %d\n",
787              win32_channel->thread_id,
788              win32_channel->fd);
789
790   if (win32_channel->data_avail_event)
791     CloseHandle (win32_channel->data_avail_event);
792   if (win32_channel->space_avail_event)
793     CloseHandle (win32_channel->space_avail_event);
794   if (win32_channel->data_avail_noticed_event)
795     CloseHandle (win32_channel->data_avail_noticed_event);
796   DeleteCriticalSection (&win32_channel->mutex);
797
798   g_free (win32_channel->buffer);
799   g_slist_free (win32_channel->watches);
800   g_free (win32_channel);
801 }
802
803 static GSource *
804 g_io_win32_msg_create_watch (GIOChannel    *channel,
805                              GIOCondition   condition)
806 {
807   GIOWin32Watch *watch;
808   GSource *source;
809
810   source = g_source_new (&g_io_watch_funcs, sizeof (GIOWin32Watch));
811   watch = (GIOWin32Watch *)source;
812   
813   watch->channel = channel;
814   g_io_channel_ref (channel);
815   
816   watch->condition = condition;
817   
818   watch->pollfd.fd = G_WIN32_MSG_HANDLE;
819   watch->pollfd.events = condition;
820   
821   g_source_add_poll (source, &watch->pollfd);
822   
823   return source;
824 }
825
826 static GIOStatus
827 g_io_win32_fd_read (GIOChannel *channel,
828                     gchar      *buf,
829                     gsize       count,
830                     gsize      *bytes_read,
831                     GError    **err)
832 {
833   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
834   gint result;
835   
836   if (win32_channel->debug)
837     g_print ("g_io_win32_fd_read: fd:%d count:%d\n",
838              win32_channel->fd, count);
839   
840   if (win32_channel->thread_id)
841     {
842       return buffer_read (win32_channel, buf, count, bytes_read, err);
843     }
844
845   result = read (win32_channel->fd, buf, count);
846
847   if (win32_channel->debug)
848     g_print ("g_io_win32_fd_read: read() = %d\n", result);
849
850   if (result < 0)
851     {
852       *bytes_read = 0;
853
854       switch(errno)
855         {
856 #ifdef EAGAIN
857           case EAGAIN:
858             return G_IO_STATUS_AGAIN;
859 #endif
860           default:
861             g_set_error (err, G_IO_CHANNEL_ERROR,
862                          g_io_channel_error_from_errno (errno),
863                          g_strerror (errno));
864             return G_IO_STATUS_ERROR;
865         }
866     }
867
868   *bytes_read = result;
869
870   return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
871 }
872
873 static GIOStatus
874 g_io_win32_fd_write (GIOChannel  *channel,
875                      const gchar *buf,
876                      gsize        count,
877                      gsize       *bytes_written,
878                      GError     **err)
879 {
880   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
881   gint result;
882   
883   result = write (win32_channel->fd, buf, count);
884   if (win32_channel->debug)
885     g_print ("g_io_win32_fd_write: fd:%d count:%d = %d\n",
886              win32_channel->fd, count, result);
887
888   if (result < 0)
889     {
890       *bytes_written = 0;
891
892       switch(errno)
893         {
894 #ifdef EAGAIN
895           case EAGAIN:
896             return G_IO_STATUS_AGAIN;
897 #endif
898           default:
899             g_set_error (err, G_IO_CHANNEL_ERROR,
900                          g_io_channel_error_from_errno (errno),
901                          g_strerror (errno));
902             return G_IO_STATUS_ERROR;
903         }
904     }
905
906   *bytes_written = result;
907
908   return G_IO_STATUS_NORMAL;
909 }
910
911 static GIOStatus
912 g_io_win32_fd_seek (GIOChannel *channel,
913                     gint64      offset,
914                     GSeekType   type,
915                     GError    **err)
916 {
917   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
918   int whence;
919   off_t tmp_offset;
920   off_t result;
921   
922   switch (type)
923     {
924     case G_SEEK_SET:
925       whence = SEEK_SET;
926       break;
927     case G_SEEK_CUR:
928       whence = SEEK_CUR;
929       break;
930     case G_SEEK_END:
931       whence = SEEK_END;
932       break;
933     default:
934       whence = -1; /* Keep the compiler quiet */
935       g_assert_not_reached();
936     }
937
938   tmp_offset = offset;
939   if (tmp_offset != offset)
940     {
941       g_set_error (err, G_IO_CHANNEL_ERROR,
942                    g_io_channel_error_from_errno (EINVAL),
943                    g_strerror (EINVAL));
944       return G_IO_STATUS_ERROR;
945     }
946   
947   result = lseek (win32_channel->fd, tmp_offset, whence);
948   
949   if (result < 0)
950     {
951       g_set_error (err, G_IO_CHANNEL_ERROR,
952                    g_io_channel_error_from_errno (errno),
953                    g_strerror (errno));
954       return G_IO_STATUS_ERROR;
955     }
956
957   return G_IO_STATUS_NORMAL;
958 }
959
960 static GIOStatus
961 g_io_win32_fd_close (GIOChannel *channel,
962                      GError    **err)
963 {
964   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
965   
966   if (win32_channel->debug)
967     g_print ("thread %#x: closing fd %d\n",
968              win32_channel->thread_id,
969              win32_channel->fd);
970   LOCK (win32_channel->mutex);
971   if (win32_channel->running)
972     {
973       if (win32_channel->debug)
974         g_print ("thread %#x: running, marking fd %d for later close\n",
975                  win32_channel->thread_id, win32_channel->fd);
976       win32_channel->running = FALSE;
977       win32_channel->needs_close = TRUE;
978       SetEvent (win32_channel->data_avail_event);
979     }
980   else
981     {
982       if (win32_channel->debug)
983         g_print ("closing fd %d\n", win32_channel->fd);
984       close (win32_channel->fd);
985       if (win32_channel->debug)
986         g_print ("closed fd %d, setting to -1\n",
987                  win32_channel->fd);
988       win32_channel->fd = -1;
989     }
990   UNLOCK (win32_channel->mutex);
991
992   /* FIXME error detection? */
993
994   return G_IO_STATUS_NORMAL;
995 }
996
997 static GSource *
998 g_io_win32_fd_create_watch (GIOChannel    *channel,
999                             GIOCondition   condition)
1000 {
1001   return g_io_win32_create_watch (channel, condition, read_thread);
1002 }
1003
1004 static GIOStatus
1005 g_io_win32_sock_read (GIOChannel *channel,
1006                       gchar      *buf,
1007                       gsize       count,
1008                       gsize      *bytes_read,
1009                       GError    **err)
1010 {
1011   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1012   gint result;
1013   GIOChannelError error;
1014
1015   if (win32_channel->debug)
1016     g_print ("g_io_win32_sock_read: sockfd:%d count:%d\n",
1017              win32_channel->fd, count);
1018 #ifdef WE_NEED_TO_HANDLE_WSAEINTR
1019 repeat:
1020 #endif
1021   result = recv (win32_channel->fd, buf, count, 0);
1022
1023   if (win32_channel->debug)
1024     g_print ("g_io_win32_sock_read: recv:%d\n", result);
1025   
1026   if (result == SOCKET_ERROR)
1027     {
1028       *bytes_read = 0;
1029
1030       switch (WSAGetLastError ())
1031         {
1032         case WSAEINVAL:
1033           error = G_IO_CHANNEL_ERROR_INVAL;
1034           break;
1035         case WSAEWOULDBLOCK:
1036           return G_IO_STATUS_AGAIN;
1037 #ifdef WE_NEED_TO_HANDLE_WSAEINTR /* not anymore with wsock2 ? */
1038         case WSAEINTR:
1039           goto repeat;
1040 #endif
1041         default:
1042           error = G_IO_CHANNEL_ERROR_FAILED;
1043           break;
1044         }
1045       g_set_error(err, G_IO_CHANNEL_ERROR, error, _("Socket error"));
1046       return G_IO_STATUS_ERROR;
1047       /* FIXME get all errors, better error messages */
1048     }
1049   else
1050     {
1051       *bytes_read = result;
1052
1053       return (result > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
1054     }
1055 }
1056
1057 static GIOStatus
1058 g_io_win32_sock_write (GIOChannel  *channel,
1059                        const gchar *buf,
1060                        gsize        count,
1061                        gsize       *bytes_written,
1062                        GError     **err)
1063 {
1064   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1065   gint result;
1066   GIOChannelError error;
1067   
1068   if (win32_channel->debug)
1069     g_print ("g_io_win32_sock_write: sockfd:%d count:%d\n",
1070              win32_channel->fd, count);
1071 #ifdef WE_NEED_TO_HANDLE_WSAEINTR
1072 repeat:
1073 #endif
1074   result = send (win32_channel->fd, buf, count, 0);
1075   
1076   if (win32_channel->debug)
1077     g_print ("g_io_win32_sock_write: send:%d\n", result);
1078   
1079   if (result == SOCKET_ERROR)
1080     {
1081       *bytes_written = 0;
1082
1083       switch (WSAGetLastError ())
1084         {
1085         case WSAEINVAL:
1086           error = G_IO_CHANNEL_ERROR_INVAL;
1087           break;
1088         case WSAEWOULDBLOCK:
1089           return G_IO_STATUS_AGAIN;
1090 #ifdef WE_NEED_TO_HANDLE_WSAEINTR /* not anymore with wsock2 ? */
1091         case WSAEINTR:
1092           goto repeat;
1093 #endif
1094         default:
1095           error = G_IO_CHANNEL_ERROR_FAILED;
1096           break;
1097         }
1098       g_set_error(err, G_IO_CHANNEL_ERROR, error, _("Socket error"));
1099       return G_IO_STATUS_ERROR;
1100       /* FIXME get all errors, better error messages */
1101     }
1102   else
1103     {
1104       *bytes_written = result;
1105
1106       return G_IO_STATUS_NORMAL;
1107     }
1108 }
1109
1110 static GIOStatus
1111 g_io_win32_sock_close (GIOChannel *channel,
1112                        GError    **err)
1113 {
1114   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1115
1116   LOCK(win32_channel->mutex);
1117   if (win32_channel->running)
1118   {
1119     if (win32_channel->debug)
1120         g_print ("thread %#x: running, marking for later close\n",
1121                  win32_channel->thread_id);
1122     win32_channel->running = FALSE;
1123     win32_channel->needs_close = TRUE;
1124     SetEvent(win32_channel->data_avail_noticed_event);
1125   }
1126   if (win32_channel->fd != -1)
1127   {
1128     if (win32_channel->debug)
1129        g_print ("thread %#x: closing socket %d\n",
1130              win32_channel->thread_id,
1131              win32_channel->fd);
1132   
1133     closesocket (win32_channel->fd);
1134     win32_channel->fd = -1;
1135   }
1136   UNLOCK(win32_channel->mutex);
1137
1138   /* FIXME error detection? */
1139
1140   return G_IO_STATUS_NORMAL;
1141 }
1142
1143 static GSource *
1144 g_io_win32_sock_create_watch (GIOChannel    *channel,
1145                               GIOCondition   condition)
1146 {
1147   return g_io_win32_create_watch (channel, condition, select_thread);
1148 }
1149
1150 GIOChannel *
1151 g_io_channel_new_file (const gchar  *filename,
1152                        const gchar  *mode,
1153                        GError      **error)
1154 {
1155   int fid, flags, pmode;
1156   GIOChannel *channel;
1157
1158   enum { /* Cheesy hack */
1159     MODE_R = 1 << 0,
1160     MODE_W = 1 << 1,
1161     MODE_A = 1 << 2,
1162     MODE_PLUS = 1 << 3,
1163   } mode_num;
1164
1165   g_return_val_if_fail (filename != NULL, NULL);
1166   g_return_val_if_fail (mode != NULL, NULL);
1167   g_return_val_if_fail ((error == NULL) || (*error == NULL), NULL);
1168
1169   switch (mode[0])
1170     {
1171       case 'r':
1172         mode_num = MODE_R;
1173         break;
1174       case 'w':
1175         mode_num = MODE_W;
1176         break;
1177       case 'a':
1178         mode_num = MODE_A;
1179         break;
1180       default:
1181         g_warning (G_STRLOC ": Invalid GIOFileMode %s.\n", mode);
1182         return NULL;
1183     }
1184
1185   switch (mode[1])
1186     {
1187       case '\0':
1188         break;
1189       case '+':
1190         if (mode[2] == '\0')
1191           {
1192             mode_num |= MODE_PLUS;
1193             break;
1194           }
1195         /* Fall through */
1196       default:
1197         g_warning (G_STRLOC ": Invalid GIOFileMode %s.\n", mode);
1198         return NULL;
1199     }
1200
1201   switch (mode_num)
1202     {
1203       case MODE_R:
1204         flags = O_RDONLY;
1205         pmode = _S_IREAD;
1206         break;
1207       case MODE_W:
1208         flags = O_WRONLY | O_TRUNC | O_CREAT;
1209         pmode = _S_IWRITE;
1210         break;
1211       case MODE_A:
1212         flags = O_WRONLY | O_APPEND | O_CREAT;
1213         pmode = _S_IWRITE;
1214         break;
1215       case MODE_R | MODE_PLUS:
1216         flags = O_RDWR;
1217         pmode = _S_IREAD | _S_IWRITE;
1218         break;
1219       case MODE_W | MODE_PLUS:
1220         flags = O_RDWR | O_TRUNC | O_CREAT;
1221         pmode = _S_IREAD | _S_IWRITE;
1222         break;
1223       case MODE_A | MODE_PLUS:
1224         flags = O_RDWR | O_APPEND | O_CREAT;
1225         pmode = _S_IREAD | _S_IWRITE;
1226         break;
1227       default:
1228         g_assert_not_reached ();
1229         flags = 0;
1230         pmode = 0;
1231     }
1232
1233   /* always open 'untranslated' */
1234   fid = open (filename, flags | _O_BINARY, pmode);
1235
1236   if (g_io_win32_get_debug_flag ())
1237     {
1238       g_print ("g_io_channel_win32_new_file: open(\"%s\", ", filename);
1239       g_win32_print_access_mode (flags|_O_BINARY);
1240       g_print (",%#o)=%d\n", pmode, fid);
1241     }
1242
1243   if (fid < 0)
1244     {
1245       g_set_error (error, G_FILE_ERROR,
1246                    g_file_error_from_errno (errno),
1247                    g_strerror (errno));
1248       return (GIOChannel *)NULL;
1249     }
1250
1251   channel = g_io_channel_win32_new_fd (fid);
1252
1253   /* XXX: move this to g_io_channel_win32_new_fd () */
1254   channel->close_on_unref = TRUE;
1255   channel->is_seekable = TRUE;
1256
1257   switch (mode_num)
1258     {
1259       case MODE_R:
1260         channel->is_readable = TRUE;
1261         channel->is_writeable = FALSE;
1262         break;
1263       case MODE_W:
1264       case MODE_A:
1265         channel->is_readable = FALSE;
1266         channel->is_writeable = TRUE;
1267         break;
1268       case MODE_R | MODE_PLUS:
1269       case MODE_W | MODE_PLUS:
1270       case MODE_A | MODE_PLUS:
1271         channel->is_readable = TRUE;
1272         channel->is_writeable = TRUE;
1273         break;
1274       default:
1275         g_assert_not_reached ();
1276     }
1277
1278   return channel;
1279 }
1280
1281 static GIOStatus
1282 g_io_win32_set_flags (GIOChannel     *channel,
1283                       GIOFlags        flags,
1284                       GError        **err)
1285 {
1286   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1287
1288   if (win32_channel->debug)
1289     {
1290       g_print ("g_io_win32_set_flags: ");
1291       g_win32_print_gioflags (flags);
1292       g_print ("\n");
1293     }
1294
1295   g_set_error (err, 
1296                G_IO_CHANNEL_ERROR, 
1297                g_file_error_from_errno (EACCES), 
1298                _("Channel set flags unsupported"));
1299   return G_IO_STATUS_ERROR;
1300 }
1301
1302 static GIOFlags
1303 g_io_win32_fd_get_flags (GIOChannel     *channel)
1304 {
1305   GIOFlags flags = 0;
1306   struct _stat st;
1307   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1308
1309   g_return_val_if_fail (win32_channel != NULL, 0);
1310   g_return_val_if_fail (win32_channel->type == G_IO_WIN32_FILE_DESC, 0);
1311
1312   if (0 == _fstat (win32_channel->fd, &st))
1313     {
1314        /* XXX: G_IO_FLAG_APPEND */
1315        /* XXX: G_IO_FLAG_NONBLOCK */
1316        if (st.st_mode & _S_IREAD)    flags |= G_IO_FLAG_IS_READABLE;
1317        if (st.st_mode & _S_IWRITE)   flags |= G_IO_FLAG_IS_WRITEABLE;
1318        /* XXX: */
1319        if (!(st.st_mode & _S_IFIFO)) flags |= G_IO_FLAG_IS_SEEKABLE;
1320     }
1321
1322   return flags;
1323 }
1324
1325 /*
1326  * Generic implementation, just translating createion flags
1327  */
1328 static GIOFlags
1329 g_io_win32_get_flags (GIOChannel     *channel)
1330 {
1331   GIOFlags flags;
1332
1333   flags =   (channel->is_readable ? G_IO_FLAG_IS_READABLE : 0)
1334           | (channel->is_writeable ? G_IO_FLAG_IS_READABLE : 0)
1335           | (channel->is_seekable ? G_IO_FLAG_IS_SEEKABLE : 0);
1336
1337   return flags;
1338 }
1339
1340 static GIOFuncs win32_channel_msg_funcs = {
1341   g_io_win32_msg_read,
1342   g_io_win32_msg_write,
1343   g_io_win32_no_seek,
1344   g_io_win32_msg_close,
1345   g_io_win32_msg_create_watch,
1346   g_io_win32_free,
1347   g_io_win32_set_flags,
1348   g_io_win32_get_flags,
1349 };
1350
1351 static GIOFuncs win32_channel_fd_funcs = {
1352   g_io_win32_fd_read,
1353   g_io_win32_fd_write,
1354   g_io_win32_fd_seek,
1355   g_io_win32_fd_close,
1356   g_io_win32_fd_create_watch,
1357   g_io_win32_free,
1358   g_io_win32_set_flags,
1359   g_io_win32_fd_get_flags,
1360 };
1361
1362 static GIOFuncs win32_channel_sock_funcs = {
1363   g_io_win32_sock_read,
1364   g_io_win32_sock_write,
1365   g_io_win32_no_seek,
1366   g_io_win32_sock_close,
1367   g_io_win32_sock_create_watch,
1368   g_io_win32_free,
1369   g_io_win32_set_flags,
1370   g_io_win32_get_flags,
1371 };
1372
1373 GIOChannel *
1374 g_io_channel_win32_new_messages (guint hwnd)
1375 {
1376   GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
1377   GIOChannel *channel = (GIOChannel *)win32_channel;
1378
1379   g_io_channel_init (channel);
1380   g_io_channel_win32_init (win32_channel);
1381   if (win32_channel->debug)
1382     g_print ("g_io_channel_win32_new_messages: hwnd = %ud\n", hwnd);
1383   channel->funcs = &win32_channel_msg_funcs;
1384   win32_channel->type = G_IO_WIN32_WINDOWS_MESSAGES;
1385   win32_channel->hwnd = (HWND) hwnd;
1386
1387   /* XXX: check this. */
1388   channel->is_readable = IsWindow (win32_channel->hwnd);
1389   channel->is_writeable = IsWindow (win32_channel->hwnd);
1390
1391   channel->is_seekable = FALSE;
1392
1393   return channel;
1394 }
1395
1396 GIOChannel *
1397 g_io_channel_win32_new_fd (gint fd)
1398 {
1399   GIOWin32Channel *win32_channel;
1400   GIOChannel *channel;
1401   struct stat st;
1402
1403   if (fstat (fd, &st) == -1)
1404     {
1405       g_warning (G_STRLOC ": %d isn't a (emulated) file descriptor", fd);
1406       return NULL;
1407     }
1408
1409   win32_channel = g_new (GIOWin32Channel, 1);
1410   channel = (GIOChannel *)win32_channel;
1411
1412   g_io_channel_init (channel);
1413   g_io_channel_win32_init (win32_channel);
1414   if (win32_channel->debug)
1415     g_print ("g_io_channel_win32_new_fd: %u\n", fd);
1416   channel->funcs = &win32_channel_fd_funcs;
1417   win32_channel->type = G_IO_WIN32_FILE_DESC;
1418   win32_channel->fd = fd;
1419
1420
1421   /* fstat doesn't deliver senseful values, but
1422    * fcntl isn't available, so guess ...
1423    */
1424   if (st.st_mode & _S_IFIFO)
1425     {
1426       channel->is_readable  = TRUE;
1427       channel->is_writeable = TRUE;
1428       channel->is_seekable  = FALSE;
1429     }
1430   else
1431     {
1432       channel->is_readable  = !!(st.st_mode & _S_IREAD);
1433       channel->is_writeable = !!(st.st_mode & _S_IWRITE);
1434       /* XXX What about "device files" (COM1: and the like) */
1435       channel->is_seekable = TRUE;
1436     }
1437
1438   return channel;
1439 }
1440
1441 gint
1442 g_io_channel_win32_get_fd (GIOChannel *channel)
1443 {
1444   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1445
1446   return win32_channel->fd;
1447 }
1448
1449 GIOChannel *
1450 g_io_channel_win32_new_socket (int socket)
1451 {
1452   GIOWin32Channel *win32_channel = g_new (GIOWin32Channel, 1);
1453   GIOChannel *channel = (GIOChannel *)win32_channel;
1454
1455   g_io_channel_init (channel);
1456   g_io_channel_win32_init (win32_channel);
1457   if (win32_channel->debug)
1458     g_print ("g_io_channel_win32_new_socket: sockfd:%d\n", socket);
1459   channel->funcs = &win32_channel_sock_funcs;
1460   win32_channel->type = G_IO_WIN32_SOCKET;
1461   win32_channel->fd = socket;
1462
1463   /* XXX: check this */
1464   channel->is_readable = TRUE;
1465   channel->is_writeable = TRUE;
1466   channel->is_seekable = FALSE;
1467
1468   return channel;
1469 }
1470
1471 GIOChannel *
1472 g_io_channel_unix_new (gint fd)
1473 {
1474   struct stat st;
1475
1476   if (fstat (fd, &st) == 0)
1477     return g_io_channel_win32_new_fd (fd);
1478   
1479   if (getsockopt (fd, SOL_SOCKET, SO_TYPE, NULL, NULL) != SO_ERROR)
1480     return g_io_channel_win32_new_socket(fd);
1481
1482   g_warning (G_STRLOC ": %d is neither a file descriptor or a socket", fd);
1483   return NULL;
1484 }
1485
1486 gint
1487 g_io_channel_unix_get_fd (GIOChannel *channel)
1488 {
1489   return g_io_channel_win32_get_fd (channel);
1490 }
1491
1492 void
1493 g_io_channel_win32_set_debug (GIOChannel *channel,
1494                               gboolean    flag)
1495 {
1496   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1497
1498   win32_channel->debug = flag;
1499 }
1500
1501 gint
1502 g_io_channel_win32_poll (GPollFD *fds,
1503                          gint     n_fds,
1504                          gint     timeout)
1505 {
1506   int result;
1507
1508   g_return_val_if_fail (n_fds >= 0, 0);
1509
1510   result = (*g_main_context_get_poll_func (NULL)) (fds, n_fds, timeout);
1511
1512   return result;
1513 }
1514
1515 void
1516 g_io_channel_win32_make_pollfd (GIOChannel   *channel,
1517                                 GIOCondition  condition,
1518                                 GPollFD      *fd)
1519 {
1520   GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
1521
1522   if (win32_channel->data_avail_event == NULL)
1523     create_events (win32_channel);
1524   
1525   fd->fd = (gint) win32_channel->data_avail_event;
1526   fd->events = condition;
1527
1528   if (win32_channel->thread_id == 0)
1529     {
1530       if ((condition & G_IO_IN) && win32_channel->type == G_IO_WIN32_FILE_DESC)
1531         create_thread (win32_channel, condition, read_thread);
1532       else if (win32_channel->type == G_IO_WIN32_SOCKET)
1533         create_thread (win32_channel, condition, select_thread);
1534     }
1535 }
1536
1537 /* Binary compatibility */
1538 GIOChannel *
1539 g_io_channel_win32_new_stream_socket (int socket)
1540 {
1541   return g_io_channel_win32_new_socket (socket);
1542 }