changeset 3240:a6af023db10d HEAD

i_stream_next_line() works now even if the stream buffer can't be directly modified.
author Timo Sirainen <tss@iki.fi>
date Tue, 29 Mar 2005 01:35:12 +0300
parents 904a268921af
children b79853b4b005
files src/lib/istream-internal.h src/lib/istream.c src/lib/istream.h
diffstat 3 files changed, 40 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/src/lib/istream-internal.h	Mon Mar 28 16:06:43 2005 +0300
+++ b/src/lib/istream-internal.h	Tue Mar 29 01:35:12 2005 +0300
@@ -19,6 +19,7 @@
 	int fd;
 	const unsigned char *buffer;
 	unsigned char *w_buffer; /* may be NULL */
+	string_t *line_str; /* for i_stream_next_line() if w_buffer == NULL */
 	size_t buffer_size;
 	uoff_t abs_start_offset;
 
--- a/src/lib/istream.c	Mon Mar 28 16:06:43 2005 +0300
+++ b/src/lib/istream.c	Tue Mar 29 01:35:12 2005 +0300
@@ -1,6 +1,7 @@
 /* Copyright (c) 2002-2003 Timo Sirainen */
 
 #include "lib.h"
+#include "str.h"
 #include "istream-internal.h"
 
 void i_stream_ref(struct istream *stream)
@@ -10,6 +11,12 @@
 
 void i_stream_unref(struct istream *stream)
 {
+	struct _istream *_stream = stream->real_stream;
+
+	if (_stream->iostream.refcount == 1) {
+		if (_stream->line_str != NULL)
+			str_free(_stream->line_str);
+	}
 	_io_stream_unref(&stream->real_stream->iostream);
 }
 
@@ -97,6 +104,36 @@
 	return !stream->eof || _stream->skip != _stream->pos;
 }
 
+static char *i_stream_next_line_finish(struct _istream *stream, size_t i)
+{
+	char *ret;
+	size_t end;
+
+	if (i > 0 && stream->buffer[i-1] == '\r')
+		end = i - 1;
+	else
+		end = i;
+
+	if (stream->w_buffer != NULL) {
+		/* modify the buffer directly */
+		stream->w_buffer[end] = '\0';
+		ret = (char *)stream->w_buffer + stream->skip;
+	} else {
+		/* use a temporary string to return it */
+		if (stream->line_str == NULL)
+			stream->line_str = str_new(default_pool, 256);
+		str_truncate(stream->line_str, 0);
+		str_append_n(stream->line_str, stream->buffer + stream->skip,
+			     end - stream->skip);
+		ret = str_c_modifyable(stream->line_str);
+	}
+
+	i++;
+	stream->istream.v_offset += i - stream->skip;
+	stream->skip = i;
+	return ret;
+}
+
 char *i_stream_next_line(struct istream *stream)
 {
 	struct _istream *_stream = stream->real_stream;
@@ -120,15 +157,7 @@
 	for (i = _stream->skip; i < _stream->pos; i++) {
 		if (_stream->buffer[i] == 10) {
 			/* got it */
-			if (i > 0 && _stream->buffer[i-1] == '\r')
-				_stream->w_buffer[i-1] = '\0';
-			else
-				_stream->w_buffer[i] = '\0';
-			ret_buf = (char *) _stream->w_buffer + _stream->skip;
-
-			i++;
-			stream->v_offset += i - _stream->skip;
-			_stream->skip = i;
+			ret_buf = i_stream_next_line_finish(_stream, i);
                         break;
 		}
 	}
--- a/src/lib/istream.h	Mon Mar 28 16:06:43 2005 +0300
+++ b/src/lib/istream.h	Tue Mar 29 01:35:12 2005 +0300
@@ -55,8 +55,7 @@
 int i_stream_have_bytes_left(struct istream *stream);
 
 /* Gets the next line from stream and returns it, or NULL if more data is
-   needed to make a full line. NOTE: modifies the data in buffer for the \0,
-   so it works only with buffered streams (currently only file). */
+   needed to make a full line. */
 char *i_stream_next_line(struct istream *stream);
 /* Like i_stream_next_line(), but reads for more data if needed. Returns NULL
    if more data is needed or error occured. */