applied patch from Andreas Persenius <ndap@swipnet.se> that updates the
[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 Lesser 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  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser 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  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
25  * file for a list of people on the GLib Team.  See the ChangeLog
26  * files for a list of changes.  These files are distributed with
27  * GLib at ftp://ftp.gtk.org/pub/gtk/. 
28  */
29
30 /* 
31  * MT safe
32  */
33
34 #include "glib.h"
35 #include <sys/types.h>
36 #include <unistd.h>
37 #include <errno.h>
38
39 /*
40  * Unix IO Channels
41  */
42
43 typedef struct _GIOUnixChannel GIOUnixChannel;
44 typedef struct _GIOUnixWatch GIOUnixWatch;
45
46 struct _GIOUnixChannel {
47   GIOChannel channel;
48   gint fd;
49 };
50
51 struct _GIOUnixWatch {
52   GPollFD       pollfd;
53   GIOChannel   *channel;
54   GIOCondition  condition;
55   GIOFunc       callback;
56 };
57
58
59 static GIOError g_io_unix_read (GIOChannel *channel, 
60                        gchar     *buf, 
61                        guint      count,
62                        guint     *bytes_written);
63                        
64 static GIOError g_io_unix_write(GIOChannel *channel, 
65                                 gchar     *buf, 
66                                 guint      count,
67                                 guint     *bytes_written);
68 static GIOError g_io_unix_seek (GIOChannel *channel,
69                                 gint      offset, 
70                                 GSeekType type);
71 static void g_io_unix_close    (GIOChannel *channel);
72 static void g_io_unix_free     (GIOChannel *channel);
73 static guint  g_io_unix_add_watch (GIOChannel      *channel,
74                                    gint           priority,
75                                    GIOCondition   condition,
76                                    GIOFunc        func,
77                                    gpointer       user_data,
78                                    GDestroyNotify notify);
79 static gboolean g_io_unix_prepare  (gpointer source_data, 
80                                     GTimeVal *current_time,
81                                     gint *timeout,
82                                     gpointer user_data);
83 static gboolean g_io_unix_check    (gpointer source_data,
84                                     GTimeVal *current_time,
85                                     gpointer user_data);
86 static gboolean g_io_unix_dispatch (gpointer source_data,
87                                     GTimeVal *current_time,
88                                     gpointer user_data);
89 static void g_io_unix_destroy  (gpointer source_data);
90
91 GSourceFuncs unix_watch_funcs = {
92   g_io_unix_prepare,
93   g_io_unix_check,
94   g_io_unix_dispatch,
95   g_io_unix_destroy
96 };
97
98 GIOFuncs unix_channel_funcs = {
99   g_io_unix_read,
100   g_io_unix_write,
101   g_io_unix_seek,
102   g_io_unix_close,
103   g_io_unix_add_watch,
104   g_io_unix_free,
105 };
106
107 static gboolean 
108 g_io_unix_prepare  (gpointer source_data, 
109                     GTimeVal *current_time,
110                     gint     *timeout,
111                     gpointer user_data)
112 {
113   *timeout = -1;
114   return FALSE;
115 }
116
117 static gboolean 
118 g_io_unix_check    (gpointer source_data,
119                     GTimeVal *current_time,
120                     gpointer user_data)
121 {
122   GIOUnixWatch *data = source_data;
123
124   return (data->pollfd.revents & data->condition);
125 }
126
127 static gboolean
128 g_io_unix_dispatch (gpointer source_data, 
129                     GTimeVal *current_time,
130                     gpointer user_data)
131
132 {
133   GIOUnixWatch *data = source_data;
134
135   return (*data->callback)(data->channel,
136                            data->pollfd.revents & data->condition,
137                            user_data);
138 }
139
140 static void 
141 g_io_unix_destroy (gpointer source_data)
142 {
143   GIOUnixWatch *data = source_data;
144
145   g_main_remove_poll (&data->pollfd);
146   g_io_channel_unref (data->channel);
147   g_free (data);
148 }
149
150 static GIOError 
151 g_io_unix_read (GIOChannel *channel, 
152                 gchar     *buf, 
153                 guint      count,
154                 guint     *bytes_read)
155 {
156   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
157   gint result;
158
159   result = read (unix_channel->fd, buf, count);
160
161   if (result < 0)
162     {
163       *bytes_read = 0;
164       switch (errno)
165         {
166         case EINVAL:
167           return G_IO_ERROR_INVAL;
168         case EAGAIN:
169         case EINTR:
170           return G_IO_ERROR_AGAIN;
171         default:
172           return G_IO_ERROR_UNKNOWN;
173         }
174     }
175   else
176     {
177       *bytes_read = result;
178       return G_IO_ERROR_NONE;
179     }
180 }
181                        
182 static GIOError 
183 g_io_unix_write(GIOChannel *channel, 
184                 gchar     *buf, 
185                 guint      count,
186                 guint     *bytes_written)
187 {
188   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
189   gint result;
190
191   result = write (unix_channel->fd, buf, count);
192
193   if (result < 0)
194     {
195       *bytes_written = 0;
196       switch (errno)
197         {
198         case EINVAL:
199           return G_IO_ERROR_INVAL;
200         case EAGAIN:
201         case EINTR:
202           return G_IO_ERROR_AGAIN;
203         default:
204           return G_IO_ERROR_UNKNOWN;
205         }
206     }
207   else
208     {
209       *bytes_written = result;
210       return G_IO_ERROR_NONE;
211     }
212 }
213
214 static GIOError 
215 g_io_unix_seek (GIOChannel *channel,
216                 gint      offset, 
217                 GSeekType type)
218 {
219   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
220   int whence;
221   off_t result;
222
223   switch (type)
224     {
225     case G_SEEK_SET:
226       whence = SEEK_SET;
227       break;
228     case G_SEEK_CUR:
229       whence = SEEK_CUR;
230       break;
231     case G_SEEK_END:
232       whence = SEEK_END;
233       break;
234     default:
235       g_warning ("g_io_unix_seek: unknown seek type");
236       return G_IO_ERROR_UNKNOWN;
237     }
238
239   result = lseek (unix_channel->fd, offset, whence);
240
241   if (result < 0)
242     {
243       switch (errno)
244         {
245         case EINVAL:
246           return G_IO_ERROR_INVAL;
247         default:
248           return G_IO_ERROR_UNKNOWN;
249         }
250     }
251   else
252     return G_IO_ERROR_NONE;
253 }
254
255
256 static void 
257 g_io_unix_close (GIOChannel *channel)
258 {
259   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
260
261   close (unix_channel->fd);
262 }
263
264 static void 
265 g_io_unix_free (GIOChannel *channel)
266 {
267   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
268
269   g_free (unix_channel);
270 }
271
272 static guint 
273 g_io_unix_add_watch (GIOChannel    *channel,
274                      gint           priority,
275                      GIOCondition   condition,
276                      GIOFunc        func,
277                      gpointer       user_data,
278                      GDestroyNotify notify)
279 {
280   GIOUnixWatch *watch = g_new (GIOUnixWatch, 1);
281   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
282   
283   watch->channel = channel;
284   g_io_channel_ref (channel);
285
286   watch->callback = func;
287   watch->condition = condition;
288
289   watch->pollfd.fd = unix_channel->fd;
290   watch->pollfd.events = condition;
291
292   g_main_add_poll (&watch->pollfd, priority);
293
294   return g_source_add (priority, TRUE, &unix_watch_funcs, watch, user_data, notify);
295 }
296
297 GIOChannel *
298 g_io_channel_unix_new (gint fd)
299 {
300   GIOUnixChannel *unix_channel = g_new (GIOUnixChannel, 1);
301   GIOChannel *channel = (GIOChannel *)unix_channel;
302
303   g_io_channel_init (channel);
304   channel->funcs = &unix_channel_funcs;
305
306   unix_channel->fd = fd;
307   return channel;
308 }
309
310 gint
311 g_io_channel_unix_get_fd (GIOChannel *channel)
312 {
313   GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
314   return unix_channel->fd;
315 }