5e62ed85b9da55ebe4c5c588a3dd271d5580053a
[platform/upstream/glib.git] / 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   GIOChannel channel;
41   gint fd;
42 };
43
44 struct _GIOUnixWatch {
45   GPollFD       pollfd;
46   GIOChannel   *channel;
47   GIOCondition  condition;
48   GIOFunc       callback;
49 };
50
51
52 static GIOError g_io_unix_read (GIOChannel *channel, 
53                        gchar     *buf, 
54                        guint      count,
55                        guint     *bytes_written);
56                        
57 static GIOError g_io_unix_write(GIOChannel *channel, 
58                                 gchar     *buf, 
59                                 guint      count,
60                                 guint     *bytes_written);
61 static GIOError g_io_unix_seek (GIOChannel *channel,
62                                 gint      offset, 
63                                 GSeekType type);
64 static void g_io_unix_close    (GIOChannel *channel);
65 static void g_io_unix_free     (GIOChannel *channel);
66 static guint  g_io_unix_add_watch (GIOChannel      *channel,
67                                    gint           priority,
68                                    GIOCondition   condition,
69                                    GIOFunc        func,
70                                    gpointer       user_data,
71                                    GDestroyNotify notify);
72 static gboolean g_io_unix_prepare  (gpointer source_data, 
73                                     GTimeVal *current_time,
74                                     gint *timeout);
75 static gboolean g_io_unix_check    (gpointer source_data,
76                                     GTimeVal *current_time);
77 static gboolean g_io_unix_dispatch (gpointer source_data,
78                                     GTimeVal *current_time,
79                                     gpointer user_data);
80 static void g_io_unix_destroy  (gpointer source_data);
81
82 GSourceFuncs unix_watch_funcs = {
83   g_io_unix_prepare,
84   g_io_unix_check,
85   g_io_unix_dispatch,
86   g_io_unix_destroy
87 };
88
89 GIOFuncs unix_channel_funcs = {
90   g_io_unix_read,
91   g_io_unix_write,
92   g_io_unix_seek,
93   g_io_unix_close,
94   g_io_unix_add_watch,
95   g_io_unix_free,
96 };
97
98 static gboolean 
99 g_io_unix_prepare  (gpointer source_data, 
100                     GTimeVal *current_time,
101                     gint    *timeout)
102 {
103   *timeout = -1;
104   return FALSE;
105 }
106
107 static gboolean 
108 g_io_unix_check    (gpointer source_data,
109                     GTimeVal *current_time)
110 {
111   GIOUnixWatch *data = source_data;
112
113   return (data->pollfd.revents & data->condition);
114 }
115
116 static gboolean
117 g_io_unix_dispatch (gpointer source_data, 
118                     GTimeVal *current_time,
119                     gpointer user_data)
120
121 {
122   GIOUnixWatch *data = source_data;
123
124   return (*data->callback)(data->channel,
125                            data->pollfd.revents & data->condition,
126                            user_data);
127 }
128
129 static void 
130 g_io_unix_destroy (gpointer source_data)
131 {
132   GIOUnixWatch *data = source_data;
133
134   g_main_remove_poll (&data->pollfd);
135   g_io_channel_unref (data->channel);
136   g_free (data);
137 }
138
139 static GIOError 
140 g_io_unix_read (GIOChannel *channel, 
141                 gchar     *buf, 
142                 guint      count,
143                 guint     *bytes_read)
144 {
145   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
146   gint result;
147
148   result = read (unix_channel->fd, buf, count);
149
150   if (result < 0)
151     {
152       *bytes_read = 0;
153       switch (errno)
154         {
155         case EINVAL:
156           return G_IO_ERROR_INVAL;
157         case EAGAIN:
158           return G_IO_ERROR_AGAIN;
159         default:
160           return G_IO_ERROR_UNKNOWN;
161         }
162     }
163   else
164     {
165       *bytes_read = result;
166       return G_IO_ERROR_NONE;
167     }
168 }
169                        
170 static GIOError 
171 g_io_unix_write(GIOChannel *channel, 
172                 gchar     *buf, 
173                 guint      count,
174                 guint     *bytes_written)
175 {
176   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
177   gint result;
178
179   result = write (unix_channel->fd, buf, count);
180
181   if (result < 0)
182     {
183       *bytes_written = 0;
184       switch (errno)
185         {
186         case EINVAL:
187           return G_IO_ERROR_INVAL;
188         case EAGAIN:
189           return G_IO_ERROR_AGAIN;
190         default:
191           return G_IO_ERROR_UNKNOWN;
192         }
193     }
194   else
195     {
196       *bytes_written = result;
197       return G_IO_ERROR_NONE;
198     }
199 }
200
201 static GIOError 
202 g_io_unix_seek (GIOChannel *channel,
203                 gint      offset, 
204                 GSeekType type)
205 {
206   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
207   int whence;
208   off_t result;
209
210   switch (type)
211     {
212     case G_SEEK_SET:
213       whence = SEEK_SET;
214       break;
215     case G_SEEK_CUR:
216       whence = SEEK_CUR;
217       break;
218     case G_SEEK_END:
219       whence = SEEK_END;
220       break;
221     default:
222       g_warning ("g_io_unix_seek: unknown seek type");
223       return G_IO_ERROR_UNKNOWN;
224     }
225
226   result = lseek (unix_channel->fd, offset, whence);
227
228   if (result < 0)
229     {
230       switch (errno)
231         {
232         case EINVAL:
233           return G_IO_ERROR_INVAL;
234         default:
235           return G_IO_ERROR_UNKNOWN;
236         }
237     }
238   else
239     return G_IO_ERROR_NONE;
240 }
241
242
243 static void 
244 g_io_unix_close (GIOChannel *channel)
245 {
246   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
247
248   close (unix_channel->fd);
249 }
250
251 static void 
252 g_io_unix_free (GIOChannel *channel)
253 {
254   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
255
256   g_free (unix_channel);
257 }
258
259 static guint 
260 g_io_unix_add_watch (GIOChannel    *channel,
261                      gint           priority,
262                      GIOCondition   condition,
263                      GIOFunc        func,
264                      gpointer       user_data,
265                      GDestroyNotify notify)
266 {
267   GIOUnixWatch *watch = g_new (GIOUnixWatch, 1);
268   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
269   
270   watch->channel = channel;
271   g_io_channel_ref (channel);
272
273   watch->callback = func;
274   watch->condition = condition;
275
276   watch->pollfd.fd = unix_channel->fd;
277   watch->pollfd.events = condition;
278
279   g_main_add_poll (&watch->pollfd, priority);
280
281   return g_source_add (priority, TRUE, &unix_watch_funcs, watch, user_data, notify);
282 }
283
284 GIOChannel *
285 g_io_channel_unix_new (gint fd)
286 {
287   GIOUnixChannel *unix_channel = g_new (GIOUnixChannel, 1);
288   GIOChannel *channel = (GIOChannel *)unix_channel;
289
290   g_io_channel_init (channel);
291   channel->funcs = &unix_channel_funcs;
292
293   unix_channel->fd = fd;
294   return channel;
295 }
296
297 gint
298 g_io_channel_unix_get_fd (GIOChannel *channel)
299 {
300   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
301   return unix_channel->fd;
302 }