[gedit/docstream2: 2/16] Use streams to save in the gio saver.
- From: Jesse van den Kieboom <jessevdk src gnome org>
- To: svn-commits-list gnome org
- Cc:
- Subject: [gedit/docstream2: 2/16] Use streams to save in the gio saver.
- Date: Sat, 23 Jan 2010 13:30:20 +0000 (UTC)
commit 2227fca3e73d04416b0717ee0eb89b693df01e70
Author: Ignacio Casal Quinteiro <icq gnome org>
Date: Tue Jan 19 15:11:26 2010 +0100
Use streams to save in the gio saver.
FIXME: the document-saver modification is for testing.
gedit/gedit-document-input-stream.c | 13 ++
gedit/gedit-document-saver.c | 4 +-
gedit/gedit-gio-document-saver.c | 249 ++++++++++++++++++++---------------
tests/document-input-stream.c | 2 +-
4 files changed, 158 insertions(+), 110 deletions(-)
---
diff --git a/gedit/gedit-document-input-stream.c b/gedit/gedit-document-input-stream.c
index 73a27eb..bd05748 100644
--- a/gedit/gedit-document-input-stream.c
+++ b/gedit/gedit-document-input-stream.c
@@ -39,6 +39,8 @@ struct _GeditDocumentInputStreamPrivate
/* store the trailing line */
gchar *line;
gsize line_len;
+
+ guint newline_added : 1;
};
enum
@@ -158,6 +160,7 @@ gedit_document_input_stream_init (GeditDocumentInputStream *stream)
stream->priv->line = NULL;
stream->priv->line_len = 0;
stream->priv->pos = NULL;
+ stream->priv->newline_added = FALSE;
}
/**
@@ -302,6 +305,15 @@ gedit_document_input_stream_read (GInputStream *stream,
space_left -= n;
} while (space_left > 0 && n != 0);
+ /* make sure files are always terminated with \n (see bug #95676). Note
+ that we strip the trailing \n when loading the file */
+ if (space_left > 0 && !dstream->priv->newline_added)
+ {
+ memcpy (buffer, "\n", 1);
+ read++;
+ dstream->priv->newline_added = TRUE;
+ }
+
return read;
}
@@ -315,6 +327,7 @@ gedit_document_input_stream_close (GInputStream *stream,
g_free (dstream->priv->line);
dstream->priv->line = NULL;
dstream->priv->line_len = 0;
+ dstream->priv->newline_added = FALSE;
return TRUE;
}
diff --git a/gedit/gedit-document-saver.c b/gedit/gedit-document-saver.c
index 1e58479..0402008 100644
--- a/gedit/gedit-document-saver.c
+++ b/gedit/gedit-document-saver.c
@@ -233,11 +233,11 @@ gedit_document_saver_new (GeditDocument *doc,
g_return_val_if_fail (GEDIT_IS_DOCUMENT (doc), NULL);
-#ifndef G_OS_WIN32
+/*#ifndef G_OS_WIN32
if (gedit_utils_uri_has_file_scheme (uri))
saver_type = GEDIT_TYPE_LOCAL_DOCUMENT_SAVER;
else
-#endif
+#endif*/
saver_type = GEDIT_TYPE_GIO_DOCUMENT_SAVER;
if (encoding == NULL)
diff --git a/gedit/gedit-gio-document-saver.c b/gedit/gedit-gio-document-saver.c
index fbd1256..a2d099c 100644
--- a/gedit/gedit-gio-document-saver.c
+++ b/gedit/gedit-gio-document-saver.c
@@ -37,19 +37,22 @@
#include <gio/gio.h>
#include <string.h>
-#include "gedit-convert.h"
#include "gedit-gio-document-saver.h"
+#include "gedit-document-input-stream.h"
#include "gedit-debug.h"
+#define WRITE_CHUNK_SIZE 8192
+
typedef struct
{
GeditGioDocumentSaver *saver;
- gchar *buffer;
+ gchar buffer[WRITE_CHUNK_SIZE];
GCancellable *cancellable;
gboolean tried_mount;
+ gsize written;
+ gsize read;
} AsyncData;
-#define WRITE_CHUNK_SIZE 8192
#define REMOTE_QUERY_ATTRIBUTES G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE "," \
G_FILE_ATTRIBUTE_TIME_MODIFIED
@@ -74,7 +77,8 @@ struct _GeditGioDocumentSaverPrivate
GFile *gfile;
GCancellable *cancellable;
- GFileOutputStream *stream;
+ GOutputStream *stream;
+ GInputStream *input;
GError *error;
};
@@ -82,26 +86,36 @@ struct _GeditGioDocumentSaverPrivate
G_DEFINE_TYPE(GeditGioDocumentSaver, gedit_gio_document_saver, GEDIT_TYPE_DOCUMENT_SAVER)
static void
-gedit_gio_document_saver_finalize (GObject *object)
+gedit_gio_document_saver_dispose (GObject *object)
{
GeditGioDocumentSaverPrivate *priv = GEDIT_GIO_DOCUMENT_SAVER (object)->priv;
- if (priv->cancellable)
+ if (priv->cancellable != NULL)
{
g_cancellable_cancel (priv->cancellable);
g_object_unref (priv->cancellable);
+ priv->cancellable = NULL;
}
- if (priv->gfile)
+ if (priv->gfile != NULL)
+ {
g_object_unref (priv->gfile);
+ priv->gfile = NULL;
+ }
- if (priv->error)
+ if (priv->error != NULL)
+ {
g_error_free (priv->error);
-
- if (priv->stream)
+ priv->error = NULL;
+ }
+
+ if (priv->stream != NULL)
+ {
g_object_unref (priv->stream);
+ priv->stream = NULL;
+ }
- G_OBJECT_CLASS (gedit_gio_document_saver_parent_class)->finalize (object);
+ G_OBJECT_CLASS (gedit_gio_document_saver_parent_class)->dispose (object);
}
static AsyncData *
@@ -111,9 +125,10 @@ async_data_new (GeditGioDocumentSaver *gvsaver)
async = g_slice_new (AsyncData);
async->saver = gvsaver;
- async->buffer = NULL;
async->cancellable = g_object_ref (gvsaver->priv->cancellable);
async->tried_mount = FALSE;
+ async->written = 0;
+ async->read = 0;
return async;
}
@@ -122,7 +137,6 @@ static void
async_data_free (AsyncData *async)
{
g_object_unref (async->cancellable);
- g_free (async->buffer);
g_slice_free (AsyncData, async);
}
@@ -132,7 +146,7 @@ gedit_gio_document_saver_class_init (GeditGioDocumentSaverClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
GeditDocumentSaverClass *saver_class = GEDIT_DOCUMENT_SAVER_CLASS (klass);
- object_class->finalize = gedit_gio_document_saver_finalize;
+ object_class->finalize = gedit_gio_document_saver_dispose;
saver_class->save = gedit_gio_document_saver_save;
saver_class->get_file_size = gedit_gio_document_saver_get_file_size;
@@ -171,9 +185,6 @@ async_failed (AsyncData *async,
remote_save_completed_or_failed (async->saver, async);
}
-/* prototype, because they call each other... isn't C lovely */
-static void write_file_chunk (AsyncData *async);
-
static void
remote_reget_info_cb (GFile *source,
GAsyncResult *res,
@@ -321,6 +332,7 @@ remote_get_info_cb (GFileOutputStream *stream,
next_callback = (GAsyncReadyCallback) close_async_ready_cb;
}
+ /* Close the main stream so the file stream is also closed */
g_output_stream_close_async (G_OUTPUT_STREAM (saver->priv->stream),
G_PRIORITY_HIGH,
async->cancellable,
@@ -328,17 +340,28 @@ remote_get_info_cb (GFileOutputStream *stream,
async);
}
+/* prototype, because they call each other... isn't C lovely */
+static void read_file_chunk (AsyncData *async);
+static void write_file_chunk (AsyncData *async);
+
static void
write_complete (AsyncData *async)
{
+ GOutputStream *file_stream;
+
/* document is succesfully saved. we know requery for the mime type and
* the mtime. I'm not sure this is actually necessary, can't we just use
* g_content_type_guess (since we have the file name and the data)
*/
gedit_debug_message (DEBUG_SAVER, "Write complete, query info on stream");
+
+ if (G_IS_FILE_OUTPUT_STREAM (async->saver->priv->stream))
+ file_stream = async->saver->priv->stream;
+ else
+ file_stream = g_filter_output_stream_get_base_stream (G_FILTER_OUTPUT_STREAM (async->saver->priv->stream));
/* query info on the stream */
- g_file_output_stream_query_info_async (async->saver->priv->stream,
+ g_file_output_stream_query_info_async (G_FILE_OUTPUT_STREAM (file_stream),
REMOTE_QUERY_ATTRIBUTES,
G_PRIORITY_HIGH,
async->cancellable,
@@ -348,23 +371,20 @@ write_complete (AsyncData *async)
static void
async_write_cb (GOutputStream *stream,
- GAsyncResult *res,
- AsyncData *async)
+ GAsyncResult *res,
+ AsyncData *async)
{
- GError *error = NULL;
GeditGioDocumentSaver *gvsaver;
gssize bytes_written;
-
- gedit_debug (DEBUG_SAVER);
-
- /* manually check cancelled state */
+ GError *error = NULL;
+
+ /* Check cancelled state manually */
if (g_cancellable_is_cancelled (async->cancellable))
{
async_data_free (async);
return;
}
- gvsaver = async->saver;
bytes_written = g_output_stream_write_finish (stream, res, &error);
gedit_debug_message (DEBUG_SAVER, "Written: %" G_GSSIZE_FORMAT, bytes_written);
@@ -375,17 +395,15 @@ async_write_cb (GOutputStream *stream,
async_failed (async, error);
return;
}
-
- gvsaver->priv->bytes_written += bytes_written;
-
- /* if nothing is written we're done */
- if (gvsaver->priv->bytes_written == gvsaver->priv->size)
+
+ gvsaver = async->saver;
+ async->written += bytes_written;
+
+ /* write again */
+ if (async->written != async->read)
{
- write_complete (async);
- return;
+ write_file_chunk (async);
}
-
- /* otherwise emit progress and write some more */
/* note that this signal blocks the write... check if it isn't
* a performance problem
@@ -394,7 +412,7 @@ async_write_cb (GOutputStream *stream,
FALSE,
NULL);
- write_file_chunk (async);
+ read_file_chunk (async);
}
static void
@@ -404,14 +422,9 @@ write_file_chunk (AsyncData *async)
gvsaver = async->saver;
- gedit_debug_message (DEBUG_SAVER,
- "Writing next chunk: %" G_GINT64_FORMAT "/%" G_GINT64_FORMAT,
- gvsaver->priv->bytes_written, gvsaver->priv->size);
-
g_output_stream_write_async (G_OUTPUT_STREAM (gvsaver->priv->stream),
- async->buffer + gvsaver->priv->bytes_written,
- MIN (WRITE_CHUNK_SIZE, gvsaver->priv->size -
- gvsaver->priv->bytes_written),
+ async->buffer + async->written,
+ async->read - async->written,
G_PRIORITY_HIGH,
async->cancellable,
(GAsyncReadyCallback) async_write_cb,
@@ -419,11 +432,70 @@ write_file_chunk (AsyncData *async)
}
static void
+async_read_cb (GInputStream *stream,
+ GAsyncResult *res,
+ AsyncData *async)
+{
+ GeditGioDocumentSaver *gvsaver;
+ GeditDocumentInputStream *dstream;
+ GError *error = NULL;
+
+ if (g_cancellable_is_cancelled (async->cancellable))
+ {
+ async_data_free (async);
+ return;
+ }
+
+ gvsaver = async->saver;
+
+ async->read = g_input_stream_read_finish (stream, res, &error);
+
+ if (error != NULL)
+ {
+ async_failed (async, error);
+ return;
+ }
+
+ /* Check if we finished reading and writing */
+ if (async->read == 0)
+ {
+ write_complete (async);
+ return;
+ }
+
+ /* Get how many chars have been read */
+ dstream = GEDIT_DOCUMENT_INPUT_STREAM (stream);
+ gvsaver->priv->bytes_written += gedit_document_input_stream_tell (dstream);
+
+ write_file_chunk (async);
+}
+
+static void
+read_file_chunk (AsyncData *async)
+{
+ GeditGioDocumentSaver *gvsaver;
+
+ gvsaver = async->saver;
+ async->written = 0;
+
+ g_input_stream_read_async (gvsaver->priv->input,
+ async->buffer,
+ WRITE_CHUNK_SIZE,
+ G_PRIORITY_HIGH,
+ async->cancellable,
+ (GAsyncReadyCallback) async_read_cb,
+ async);
+}
+
+static void
async_replace_ready_callback (GFile *source,
GAsyncResult *res,
AsyncData *async)
{
GeditGioDocumentSaver *gvsaver;
+ GeditDocumentSaver *saver;
+ GCharsetConverter *converter;
+ GFileOutputStream *file_stream;
GError *error = NULL;
/* Check cancelled state manually */
@@ -434,71 +506,48 @@ async_replace_ready_callback (GFile *source,
}
gvsaver = async->saver;
- gvsaver->priv->stream = g_file_replace_finish (source, res, &error);
+ saver = GEDIT_DOCUMENT_SAVER (gvsaver);
+ file_stream = g_file_replace_finish (source, res, &error);
/* handle any error that might occur */
- if (!gvsaver->priv->stream)
+ if (!file_stream)
{
gedit_debug_message (DEBUG_SAVER, "Opening file failed: %s", error->message);
async_failed (async, error);
return;
}
- /* now that we have the stream, start writing async to it */
- write_file_chunk (async);
-}
-
-/* returns a pointer to the reallocated buffer */
-static gchar *
-append_new_line (GeditGioDocumentSaver *gvsaver,
- gchar *buffer,
- gsize *len,
- GError **error)
-{
- GeditDocumentSaver *saver = GEDIT_DOCUMENT_SAVER (gvsaver);
- gsize n_len;
- gchar *n_buffer;
- gchar *res;
-
- res = buffer;
+ /* FIXME: manage converter error? */
+ gedit_debug_message (DEBUG_SAVER, "Encoding charset: %s",
+ gedit_encoding_get_charset (saver->encoding));
- n_buffer = gedit_document_saver_get_end_newline (saver, &n_len);
- if (n_buffer != NULL)
+ if (saver->encoding != gedit_encoding_get_utf8 ())
{
- gchar *new_buffer;
-
- new_buffer = g_try_realloc (buffer, *len + n_len + 1);
-
- if (new_buffer == NULL)
- {
- /* we do not error out, just use the buffer
- without the ending newline */
- g_free (n_buffer);
- g_warning ("Cannot add '\\n' at the end of the file.");
-
- return res;
- }
-
- /* Copy newline */
- memcpy (new_buffer + *len, n_buffer, n_len);
- g_free (n_buffer);
- *len += n_len;
-
- new_buffer[*len] = '\0';
-
- res = new_buffer;
+ converter = g_charset_converter_new (gedit_encoding_get_charset (saver->encoding),
+ "UTF-8",
+ NULL);
+ gvsaver->priv->stream = g_converter_output_stream_new (G_OUTPUT_STREAM (file_stream),
+ G_CONVERTER (converter));
+
+ g_object_unref (file_stream);
+ g_object_unref (converter);
}
+ else
+ {
+ gvsaver->priv->stream = G_OUTPUT_STREAM (file_stream);
+ }
+
+ gvsaver->priv->input = gedit_document_input_stream_new (GTK_TEXT_BUFFER (saver->document));
+
+ gvsaver->priv->size = gedit_document_input_stream_get_total_size (GEDIT_DOCUMENT_INPUT_STREAM (gvsaver->priv->input));
- return res;
+ read_file_chunk (async);
}
static void
begin_write (AsyncData *async)
{
GeditGioDocumentSaver *gvsaver;
- gchar *buffer;
- gsize len;
- GError *error = NULL;
gedit_debug_message (DEBUG_SAVER, "Start replacing file contents");
@@ -506,25 +555,11 @@ begin_write (AsyncData *async)
* backup as of yet
*/
gvsaver = async->saver;
- buffer = gedit_document_saver_get_document_contents (GEDIT_DOCUMENT_SAVER (gvsaver), &len, &error);
- if (buffer != NULL && len > 0)
- {
- /* Append new line to buffer */
- buffer = append_new_line (gvsaver, buffer, &len, &error);
- }
-
- if (!buffer)
- {
- async_failed (async, error);
- return;
- }
-
- async->buffer = buffer;
- gvsaver->priv->size = len;
gedit_debug_message (DEBUG_SAVER, "File contents size: %" G_GINT64_FORMAT, gvsaver->priv->size);
gedit_debug_message (DEBUG_SAVER, "Calling replace_async");
+ /* FIXME: when do we want to make a backup? */
g_file_replace_async (gvsaver->priv->gfile,
NULL,
FALSE,
@@ -580,9 +615,9 @@ recover_not_mounted (AsyncData *async)
mount_operation,
async->cancellable,
(GAsyncReadyCallback) mount_ready_callback,
- async);
+ async);
- g_object_unref (mount_operation);
+ g_object_unref (mount_operation);
}
static void
diff --git a/tests/document-input-stream.c b/tests/document-input-stream.c
index 5af9a44..ea2d6aa 100644
--- a/tests/document-input-stream.c
+++ b/tests/document-input-stream.c
@@ -83,7 +83,7 @@ test_consecutive_read ()
g_assert_cmpint (n, >, 0);
- g_assert_cmpstr (b, ==, TEXT_TO_TEST);
+ g_assert_cmpstr (b, ==, TEXT_TO_TEST"\n");
}
static void
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]