giounix.c 6.91 KB
Newer Older
1 2 3 4 5 6 7
/* GLIB - Library of useful routines for C programming
 * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * giounix.c: IO Channels using unix file descriptors
 * Copyright 1998 Owen Taylor
 *
 * This library is free software; you can redistribute it and/or
8
 * modify it under the terms of the GNU Lesser General Public
9 10 11 12 13 14
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * 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 19 20 21 22
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA 02111-1307, USA.
 */

23
/*
24
 * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
25 26 27 28 29
 * file for a list of people on the GLib Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GLib at ftp://ftp.gtk.org/pub/gtk/. 
 */

30 31 32 33
/* 
 * MT safe
 */

34 35 36 37 38 39 40 41 42 43 44 45 46
#include "glib.h"
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>

/*
 * Unix IO Channels
 */

typedef struct _GIOUnixChannel GIOUnixChannel;
typedef struct _GIOUnixWatch GIOUnixWatch;

struct _GIOUnixChannel {
47
  GIOChannel channel;
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80
  gint fd;
};

struct _GIOUnixWatch {
  GPollFD       pollfd;
  GIOChannel   *channel;
  GIOCondition  condition;
  GIOFunc       callback;
};


static GIOError g_io_unix_read (GIOChannel *channel, 
		       gchar     *buf, 
		       guint      count,
		       guint     *bytes_written);
		       
static GIOError g_io_unix_write(GIOChannel *channel, 
				gchar     *buf, 
				guint      count,
				guint     *bytes_written);
static GIOError g_io_unix_seek (GIOChannel *channel,
				gint      offset, 
				GSeekType type);
static void g_io_unix_close    (GIOChannel *channel);
static void g_io_unix_free     (GIOChannel *channel);
static guint  g_io_unix_add_watch (GIOChannel      *channel,
				   gint           priority,
				   GIOCondition   condition,
				   GIOFunc        func,
				   gpointer       user_data,
				   GDestroyNotify notify);
static gboolean g_io_unix_prepare  (gpointer source_data, 
				    GTimeVal *current_time,
81 82
				    gint *timeout,
				    gpointer user_data);
83
static gboolean g_io_unix_check    (gpointer source_data,
84 85
				    GTimeVal *current_time,
				    gpointer user_data);
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
static gboolean g_io_unix_dispatch (gpointer source_data,
				    GTimeVal *current_time,
				    gpointer user_data);
static void g_io_unix_destroy  (gpointer source_data);

GSourceFuncs unix_watch_funcs = {
  g_io_unix_prepare,
  g_io_unix_check,
  g_io_unix_dispatch,
  g_io_unix_destroy
};

GIOFuncs unix_channel_funcs = {
  g_io_unix_read,
  g_io_unix_write,
  g_io_unix_seek,
  g_io_unix_close,
  g_io_unix_add_watch,
  g_io_unix_free,
};

static gboolean 
g_io_unix_prepare  (gpointer source_data, 
		    GTimeVal *current_time,
110 111
		    gint     *timeout,
		    gpointer user_data)
112 113 114 115 116 117 118
{
  *timeout = -1;
  return FALSE;
}

static gboolean 
g_io_unix_check    (gpointer source_data,
119 120
		    GTimeVal *current_time,
		    gpointer user_data)
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
{
  GIOUnixWatch *data = source_data;

  return (data->pollfd.revents & data->condition);
}

static gboolean
g_io_unix_dispatch (gpointer source_data, 
		    GTimeVal *current_time,
		    gpointer user_data)

{
  GIOUnixWatch *data = source_data;

  return (*data->callback)(data->channel,
			   data->pollfd.revents & data->condition,
			   user_data);
}

static void 
g_io_unix_destroy (gpointer source_data)
{
  GIOUnixWatch *data = source_data;

145
  g_main_remove_poll (&data->pollfd);
146 147 148 149 150 151 152 153 154 155
  g_io_channel_unref (data->channel);
  g_free (data);
}

static GIOError 
g_io_unix_read (GIOChannel *channel, 
		gchar     *buf, 
		guint      count,
		guint     *bytes_read)
{
156
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
157 158 159 160 161 162 163 164 165 166 167 168
  gint result;

  result = read (unix_channel->fd, buf, count);

  if (result < 0)
    {
      *bytes_read = 0;
      switch (errno)
	{
	case EINVAL:
	  return G_IO_ERROR_INVAL;
	case EAGAIN:
169
	case EINTR:
170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187
	  return G_IO_ERROR_AGAIN;
	default:
	  return G_IO_ERROR_UNKNOWN;
	}
    }
  else
    {
      *bytes_read = result;
      return G_IO_ERROR_NONE;
    }
}
		       
static GIOError 
g_io_unix_write(GIOChannel *channel, 
		gchar     *buf, 
		guint      count,
		guint     *bytes_written)
{
188
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
189 190 191 192 193 194 195 196 197 198 199 200
  gint result;

  result = write (unix_channel->fd, buf, count);

  if (result < 0)
    {
      *bytes_written = 0;
      switch (errno)
	{
	case EINVAL:
	  return G_IO_ERROR_INVAL;
	case EAGAIN:
201
	case EINTR:
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
	  return G_IO_ERROR_AGAIN;
	default:
	  return G_IO_ERROR_UNKNOWN;
	}
    }
  else
    {
      *bytes_written = result;
      return G_IO_ERROR_NONE;
    }
}

static GIOError 
g_io_unix_seek (GIOChannel *channel,
		gint      offset, 
		GSeekType type)
{
219
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258
  int whence;
  off_t result;

  switch (type)
    {
    case G_SEEK_SET:
      whence = SEEK_SET;
      break;
    case G_SEEK_CUR:
      whence = SEEK_CUR;
      break;
    case G_SEEK_END:
      whence = SEEK_END;
      break;
    default:
      g_warning ("g_io_unix_seek: unknown seek type");
      return G_IO_ERROR_UNKNOWN;
    }

  result = lseek (unix_channel->fd, offset, whence);

  if (result < 0)
    {
      switch (errno)
	{
	case EINVAL:
	  return G_IO_ERROR_INVAL;
	default:
	  return G_IO_ERROR_UNKNOWN;
	}
    }
  else
    return G_IO_ERROR_NONE;
}


static void 
g_io_unix_close (GIOChannel *channel)
{
259
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
260 261 262 263 264 265 266

  close (unix_channel->fd);
}

static void 
g_io_unix_free (GIOChannel *channel)
{
267
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
268 269 270 271 272 273 274 275 276 277 278 279 280

  g_free (unix_channel);
}

static guint 
g_io_unix_add_watch (GIOChannel    *channel,
		     gint           priority,
		     GIOCondition   condition,
		     GIOFunc        func,
		     gpointer       user_data,
		     GDestroyNotify notify)
{
  GIOUnixWatch *watch = g_new (GIOUnixWatch, 1);
281
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
282 283 284 285 286 287 288 289 290 291
  
  watch->channel = channel;
  g_io_channel_ref (channel);

  watch->callback = func;
  watch->condition = condition;

  watch->pollfd.fd = unix_channel->fd;
  watch->pollfd.events = condition;

292
  g_main_add_poll (&watch->pollfd, priority);
293 294 295 296 297 298 299 300

  return g_source_add (priority, TRUE, &unix_watch_funcs, watch, user_data, notify);
}

GIOChannel *
g_io_channel_unix_new (gint fd)
{
  GIOUnixChannel *unix_channel = g_new (GIOUnixChannel, 1);
301 302 303 304
  GIOChannel *channel = (GIOChannel *)unix_channel;

  g_io_channel_init (channel);
  channel->funcs = &unix_channel_funcs;
305 306

  unix_channel->fd = fd;
307
  return channel;
308 309 310 311 312
}

gint
g_io_channel_unix_get_fd (GIOChannel *channel)
{
Sebastian Wilhelmi's avatar
Sebastian Wilhelmi committed
313
  GIOUnixChannel *unix_channel = (GIOUnixChannel *)channel;
314 315
  return unix_channel->fd;
}