diff options
author | Behdad Esfahbod <behdad@behdad.org> | 2009-09-12 18:22:16 -0400 |
---|---|---|
committer | Behdad Esfahbod <behdad@behdad.org> | 2009-09-15 21:26:41 -0400 |
commit | a63c3d687408a9e21535df84855e00564c4f0905 (patch) | |
tree | 09a8267a55015d37934c34ef9fb8de94baeaa51f | |
parent | 9de9d2de44d4723935176c71f8f09a90f15e678a (diff) |
[stream] Add file stream
-rw-r--r-- | src/Makefile.am | 2 | ||||
-rw-r--r-- | src/vtestream-base.h | 51 | ||||
-rw-r--r-- | src/vtestream-file.h | 215 | ||||
-rw-r--r-- | src/vtestream.c | 31 | ||||
-rw-r--r-- | src/vtestream.h | 6 |
5 files changed, 278 insertions, 27 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 97218f8..453f8d9 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -77,6 +77,8 @@ libvte_la_SOURCES = \ vteskel.h \ vtestream.c \ vtestream.h \ + vtestream-base.h \ + vtestream-file.h \ vtetc.c \ vtetc.h \ vtetree.c \ diff --git a/src/vtestream-base.h b/src/vtestream-base.h new file mode 100644 index 0000000..b6c6596 --- /dev/null +++ b/src/vtestream-base.h @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2009 Red Hat, Inc. + * + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Red Hat Author(s): Behdad Esfahbod + */ + +#include <glib-object.h> + +/* + * VteStream: Abstract base stream class + */ + +struct _VteStream { + GObject parent; +}; + +typedef struct _VteStreamClass { + void (*add) (VteStream *stream, const char *data, gsize len); + void (*read) (VteStream *stream, gsize offset, char *data, gsize len); + void (*trunc) (VteStream *stream, gsize offset); + void (*newpage) (VteStream *stream); +} VteStreamClass; + +static GType _vte_stream_get_type (void); +#define VTE_TYPE_STREAM _vte_stream_get_type () + +G_DEFINE_ABSTRACT_TYPE (VteStream, _vte_stream, G_TYPE_OBJECT) + +static void +_vte_stream_class_init (VteStreamClass *klass) +{ +} + +static void +_vte_stream_init (VteStream *stream) +{ +} diff --git a/src/vtestream-file.h b/src/vtestream-file.h new file mode 100644 index 0000000..64d285a --- /dev/null +++ b/src/vtestream-file.h @@ -0,0 +1,215 @@ +/* + * Copyright (C) 2009 Red Hat, Inc. + * + * This is free software; you can redistribute it and/or modify it under + * the terms of the GNU Library General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Red Hat Author(s): Behdad Esfahbod + */ + +#include <string.h> +#include <unistd.h> +#include <errno.h> + +/* + * VteFileStream: A POSIX file-based stream + */ + +typedef struct _VteFileStream { + VteStream parent; + + /* The first fd/offset is for the write head, second is for last page */ + gint fd[2]; + gsize offset[2]; +} VteFileStream; + +typedef VteStreamClass VteFileStreamClass; + +static GType _vte_file_stream_get_type (void); +#define VTE_TYPE_FILE_STREAM _vte_file_stream_get_type () + +G_DEFINE_ABSTRACT_TYPE (VteFileStream, _vte_file_stream, VTE_TYPE_STREAM) + +static void +_vte_file_stream_init (VteFileStream *stream) +{ +} + +VteStream * +_vte_file_stream_new (void) +{ + return (VteStream *) g_object_new (VTE_TYPE_FILE_STREAM, NULL); +} + +static void +_vte_file_stream_finalize (GObject *object) +{ + VteFileStream *stream = (VteFileStream *) object; + + if (stream->fd[0]) close (stream->fd[0]); + if (stream->fd[1]) close (stream->fd[1]); + + G_OBJECT_CLASS (_vte_file_stream_parent_class)->finalize(object); +} + +static inline void +_vte_file_stream_ensure_fd0 (VteFileStream *stream) +{ + gint fd; + gchar *file_name; + if (G_LIKELY (stream->fd[0])) + return; + + fd = g_file_open_tmp ("vteXXXXXX", &file_name, NULL); + if (fd != -1) { + unlink (file_name); + g_free (file_name); + } + + stream->fd[0] = dup (fd); /* we do the dup to make sure ->fd[0] is not 0 */ + + close (fd); +} + +static void +_xwrite (int fd, const char *data, gsize len) +{ + gsize ret; + while (len) { + ret = write (fd, data, len); + if (G_UNLIKELY (ret == (gsize) -1)) { + if (errno == EINTR) + continue; + else + break; + } + data += ret; + len -= ret; + } +} + +static void +_vte_file_stream_add (VteStream *astream, const char *data, gsize len) +{ + VteFileStream *stream = (VteFileStream *) astream; + + _vte_file_stream_ensure_fd0 (stream); + + lseek (stream->fd[0], 0, SEEK_END); + _xwrite (stream->fd[0], data, len); +} + +static gsize +_xread (int fd, char *data, gsize len) +{ + gsize ret, total = 0; + while (len) { + ret = read (fd, data, len); + if (G_UNLIKELY (ret == (gsize) -1)) { + if (errno == EINTR) + continue; + else + break; + } + data += ret; + len -= ret; + total += ret; + } + return total; +} + +static void +_vte_file_stream_read (VteStream *astream, gsize offset, char *data, gsize len) +{ + VteFileStream *stream = (VteFileStream *) astream; + gsize l; + + if (G_UNLIKELY (offset < stream->offset[1])) { + l = MIN (len, stream->offset[1] - offset); + memset (data, 0, l); + offset += l; data += l; len -= l; if (!len) return; + } + + if (offset < stream->offset[0]) { + lseek (stream->fd[1], offset - stream->offset[1], SEEK_SET); + l = _xread (stream->fd[1], data, len); + offset += l; data += l; len -= l; if (!len) return; + } + + lseek (stream->fd[0], offset - stream->offset[0], SEEK_SET); + l = _xread (stream->fd[0], data, len); + offset += l; data += l; len -= l; if (!len) return; + + memset (data, 0, len); +} + +static void +_vte_file_stream_swap_fds (VteFileStream *stream) +{ + gint fd; + + fd = stream->fd[0]; stream->fd[0] = stream->fd[1]; stream->fd[1] = fd; +} + +static void +_xtruncate (gint fd, gsize offset) +{ + int ret; + do { + ret = ftruncate (fd, offset); + } while (ret == -1 && errno == EINTR); +} + +static void +_vte_file_stream_trunc (VteStream *astream, gsize offset) +{ + VteFileStream *stream = (VteFileStream *) astream; + + if (G_UNLIKELY (offset < stream->offset[1])) { + _xtruncate (stream->fd[1], 0); + stream->offset[1] = offset; + } + + if (G_UNLIKELY (offset < stream->offset[0])) { + _xtruncate (stream->fd[0], 0); + stream->offset[0] = stream->offset[1]; + _vte_file_stream_swap_fds (stream); + } else { + _xtruncate (stream->fd[0], offset - stream->offset[0]); + } +} + +static void +_vte_file_stream_newpage (VteStream *astream) +{ + VteFileStream *stream = (VteFileStream *) astream; + + stream->offset[1] = stream->offset[0]; + _vte_file_stream_swap_fds (stream); + if (stream->fd[0]) + _xtruncate (stream->fd[0], 0); +} + +static void +_vte_file_stream_class_init (VteFileStreamClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->finalize = _vte_file_stream_finalize; + + klass->add = _vte_file_stream_add; + klass->read = _vte_file_stream_read; + klass->trunc = _vte_file_stream_trunc; + klass->newpage = _vte_file_stream_newpage; +} diff --git a/src/vtestream.c b/src/vtestream.c index 705384e..8b31c9a 100644 --- a/src/vtestream.c +++ b/src/vtestream.c @@ -23,33 +23,12 @@ #include "debug.h" #include "vtestream.h" -#include <glib-object.h> /* - * VteStream: Abstract base stream class + * Note: Lot of this should have become possible using gio, not sure though. + * In paticular, I don't see input+output streams in gio, so we probably would + * have to reinvent it all ourselves anyway. */ -typedef GObject VteStream; - -typedef struct _VteStreamClass { - void (*add) (const char *data, gsize len); - void (*read) (gsize offset, char *data, gsize len); - void (*trunc) (gsize len); - void (*newpage) (void); -} VteStreamClass; - -static GType _vte_stream_get_type (void); -#define VTE_TYPE_STREAM _vte_stream_get_type () - -G_DEFINE_ABSTRACT_TYPE (VteStream, _vte_stream, G_TYPE_OBJECT) - -static void -_vte_stream_class_init (VteStreamClass *klass) -{ -} - -static void -_vte_stream_init (VteStream *stream) -{ -} - +#include "vtestream-base.h" +#include "vtestream-file.h" diff --git a/src/vtestream.h b/src/vtestream.h index 65fa892..447fa3b 100644 --- a/src/vtestream.h +++ b/src/vtestream.h @@ -21,10 +21,14 @@ #ifndef vtestream_h_included #define vtestream_h_included -#include <glib.h> +#include <glib-object.h> G_BEGIN_DECLS +typedef struct _VteStream VteStream; + +VteStream * +_vte_file_stream_new (void); G_END_DECLS |