This commit merges the glib-threads branch into the main
[platform/upstream/glib.git] / glib / giounix.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * giounix.c: IO Channels using unix file descriptors
5  * Copyright 1998 Owen Taylor
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 /* 
24  * MT safe
25  */
26
27 #include "glib.h"
28 #include <sys/types.h>
29 #include <unistd.h>
30 #include <errno.h>
31
32 /*
33  * Unix IO Channels
34  */
35
36 typedef struct _GIOUnixChannel GIOUnixChannel;
37 typedef struct _GIOUnixWatch GIOUnixWatch;
38
39 struct _GIOUnixChannel {
40   gint fd;
41 };
42
43 struct _GIOUnixWatch {
44   GPollFD       pollfd;
45   GIOChannel   *channel;
46   GIOCondition  condition;
47   GIOFunc       callback;
48 };
49
50
51 static GIOError g_io_unix_read (GIOChannel *channel, 
52                        gchar     *buf, 
53                        guint      count,
54                        guint     *bytes_written);
55                        
56 static GIOError g_io_unix_write(GIOChannel *channel, 
57                                 gchar     *buf, 
58                                 guint      count,
59                                 guint     *bytes_written);
60 static GIOError g_io_unix_seek (GIOChannel *channel,
61                                 gint      offset, 
62                                 GSeekType type);
63 static void g_io_unix_close    (GIOChannel *channel);
64 static void g_io_unix_free     (GIOChannel *channel);
65 static guint  g_io_unix_add_watch (GIOChannel      *channel,
66                                    gint           priority,
67                                    GIOCondition   condition,
68                                    GIOFunc        func,
69                                    gpointer       user_data,
70                                    GDestroyNotify notify);
71 static gboolean g_io_unix_prepare  (gpointer source_data, 
72                                     GTimeVal *current_time,
73                                     gint *timeout);
74 static gboolean g_io_unix_check    (gpointer source_data,
75                                     GTimeVal *current_time);
76 static gboolean g_io_unix_dispatch (gpointer source_data,
77                                     GTimeVal *current_time,
78                                     gpointer user_data);
79 static void g_io_unix_destroy  (gpointer source_data);
80
81 GSourceFuncs unix_watch_funcs = {
82   g_io_unix_prepare,
83   g_io_unix_check,
84   g_io_unix_dispatch,
85   g_io_unix_destroy
86 };
87
88 GIOFuncs unix_channel_funcs = {
89   g_io_unix_read,
90   g_io_unix_write,
91   g_io_unix_seek,
92   g_io_unix_close,
93   g_io_unix_add_watch,
94   g_io_unix_free,
95 };
96
97 static gboolean 
98 g_io_unix_prepare  (gpointer source_data, 
99                     GTimeVal *current_time,
100                     gint    *timeout)
101 {
102   *timeout = -1;
103   return FALSE;
104 }
105
106 static gboolean 
107 g_io_unix_check    (gpointer source_data,
108                     GTimeVal *current_time)
109 {
110   GIOUnixWatch *data = source_data;
111
112   return (data->pollfd.revents & data->condition);
113 }
114
115 static gboolean
116 g_io_unix_dispatch (gpointer source_data, 
117                     GTimeVal *current_time,
118                     gpointer user_data)
119
120 {
121   GIOUnixWatch *data = source_data;
122
123   return (*data->callback)(data->channel,
124                            data->pollfd.revents & data->condition,
125                            user_data);
126 }
127
128 static void 
129 g_io_unix_destroy (gpointer source_data)
130 {
131   GIOUnixWatch *data = source_data;
132
133   g_main_poll_remove (&data->pollfd);
134   g_io_channel_unref (data->channel);
135   g_free (data);
136 }
137
138 static GIOError 
139 g_io_unix_read (GIOChannel *channel, 
140                 gchar     *buf, 
141                 guint      count,
142                 guint     *bytes_read)
143 {
144   GIOUnixChannel *unix_channel = channel->channel_data;
145   gint result;
146
147   result = read (unix_channel->fd, buf, count);
148
149   if (result < 0)
150     {
151       *bytes_read = 0;
152       switch (errno)
153         {
154         case EINVAL:
155           return G_IO_ERROR_INVAL;
156         case EAGAIN:
157           return G_IO_ERROR_AGAIN;
158         default:
159           return G_IO_ERROR_UNKNOWN;
160         }
161     }
162   else
163     {
164       *bytes_read = result;
165       return G_IO_ERROR_NONE;
166     }
167 }
168                        
169 static GIOError 
170 g_io_unix_write(GIOChannel *channel, 
171                 gchar     *buf, 
172                 guint      count,
173                 guint     *bytes_written)
174 {
175   GIOUnixChannel *unix_channel = channel->channel_data;
176   gint result;
177
178   result = write (unix_channel->fd, buf, count);
179
180   if (result < 0)
181     {
182       *bytes_written = 0;
183       switch (errno)
184         {
185         case EINVAL:
186           return G_IO_ERROR_INVAL;
187         case EAGAIN:
188           return G_IO_ERROR_AGAIN;
189         default:
190           return G_IO_ERROR_UNKNOWN;
191         }
192     }
193   else
194     {
195       *bytes_written = result;
196       return G_IO_ERROR_NONE;
197     }
198 }
199
200 static GIOError 
201 g_io_unix_seek (GIOChannel *channel,
202                 gint      offset, 
203                 GSeekType type)
204 {
205   GIOUnixChannel *unix_channel = channel->channel_data;
206   int whence;
207   off_t result;
208
209   switch (type)
210     {
211     case G_SEEK_SET:
212       whence = SEEK_SET;
213       break;
214     case G_SEEK_CUR:
215       whence = SEEK_CUR;
216       break;
217     case G_SEEK_END:
218       whence = SEEK_END;
219       break;
220     default:
221       g_warning ("g_io_unix_seek: unknown seek type");
222       return G_IO_ERROR_UNKNOWN;
223     }
224
225   result = lseek (unix_channel->fd, offset, whence);
226
227   if (result < 0)
228     {
229       switch (errno)
230         {
231         case EINVAL:
232           return G_IO_ERROR_INVAL;
233         default:
234           return G_IO_ERROR_UNKNOWN;
235         }
236     }
237   else
238     return G_IO_ERROR_NONE;
239 }
240
241
242 static void 
243 g_io_unix_close (GIOChannel *channel)
244 {
245   GIOUnixChannel *unix_channel = channel->channel_data;
246
247   close (unix_channel->fd);
248 }
249
250 static void 
251 g_io_unix_free (GIOChannel *channel)
252 {
253   GIOUnixChannel *unix_channel = channel->channel_data;
254
255   g_free (unix_channel);
256 }
257
258 static guint 
259 g_io_unix_add_watch (GIOChannel    *channel,
260                      gint           priority,
261                      GIOCondition   condition,
262                      GIOFunc        func,
263                      gpointer       user_data,
264                      GDestroyNotify notify)
265 {
266   GIOUnixWatch *watch = g_new (GIOUnixWatch, 1);
267   GIOUnixChannel *unix_channel = channel->channel_data;
268   
269   watch->channel = channel;
270   g_io_channel_ref (channel);
271
272   watch->callback = func;
273   watch->condition = condition;
274
275   watch->pollfd.fd = unix_channel->fd;
276   watch->pollfd.events = condition;
277
278   g_main_poll_add (priority, &watch->pollfd);
279
280   return g_source_add (priority, TRUE, &unix_watch_funcs, watch, user_data, notify);
281 }
282
283 GIOChannel *
284 g_io_channel_unix_new (gint fd)
285 {
286   GIOUnixChannel *unix_channel = g_new (GIOUnixChannel, 1);
287
288   unix_channel->fd = fd;
289   return g_io_channel_new (&unix_channel_funcs, unix_channel);
290 }
291
292 gint
293 g_io_channel_unix_get_fd (GIOChannel *channel)
294 {
295   GIOUnixChannel *unix_channel = channel->channel_data;
296   return unix_channel->fd;
297 }