Author: stsp
Date: Mon Jan  4 13:59:38 2010
New Revision: 895628

URL: http://svn.apache.org/viewvc?rev=895628&view=rev
Log:
Follow-up to r895469 and r895534:
Make svn_stream_mark() return a freshly allocated mark to the caller,
rather than remembering the mark in the stream's baton. This makes
nested calls to svn_stream_mark() possible.
Instead of overloading svn_stream_reset() for the purpose of seeking
back to a mark, introduce svn_stream_seek().

* subversion/include/svn_error_codes.h
  (SVN_ERR_STREAM_MARK_NOT_SUPPORTED,
   SVN_ERR_STREAM_MARK_ALREADY_SET): Remove.
  (SVN_ERR_STREAM_SEEK_NOT_SUPPORTED): New.

* subversion/include/svn_io.h
  (svn_stream_mark_t, svn_io_seek_fn_t): New types.
  (svn_io_mark_fn_t, svn_stream_mark): Replace SET argument with MARK
   and POOL arguments. Update docstring.
  (svn_stream_set_seek, svn_stream_seek): Declare.
  (svn_stream_reset): Revert docstring change from r895469.

* subversion/libsvn_subr/stream.c
  (svn_stream_t): Add seek_fn field.
  (svn_stream_mark_t): New type.
  (svn_stream_create): Initialise seek_fn field.
  (svn_stream_set_seek, svn_stream_seek, seek_handler_empty,
   seek_handler_disown, seek_handler_apr, seek_handler_stringbuf): New.
  (svn_stream_mark, mark_handler_empty, mark_handler_disown,
   mark_handler_apr, mark_handler_stringbuf): Replace SET argument with
   MARK and POOL arguments. Instead of remembering the mark in the stream
   baton, allocate a mark in POOL and return it to the caller.
  (scan_eol): Add a POOL argument to pass on to svn_stream_mark().
   Call svn_stream_seek() rather than svn_stream_reset() to rewind the stream.
  (svn_stream_empty, svn_stream_disown): Set seek function.
  (baton_apr, stringbuf_stream_baton): Remove mark field.
  (reset_handler_apr, reset_handler_stringbuf): Revert changes made in r895469.
  (svn_stream_from_aprfile2, svn_stream_from_aprfile_range_readonly,
   svn_stream_from_stringbuf): Track field-removal from baton_apr and
   stringbuf_stream_baton, set seek function.

* subversion/tests/libsvn_subr/stream-test.c
  (test_stream_mark_file, test_stream_mark_stringbuf): Rename to ...
  (test_stream_seek_file, test_stream_seek_stringbuf): ... these,
   and update to use new stream seeking API.
  (test_funcs): Track function renaming.

Modified:
    subversion/trunk/subversion/include/svn_error_codes.h
    subversion/trunk/subversion/include/svn_io.h
    subversion/trunk/subversion/libsvn_subr/stream.c
    subversion/trunk/subversion/tests/libsvn_subr/stream-test.c

Modified: subversion/trunk/subversion/include/svn_error_codes.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_error_codes.h?rev=895628&r1=895627&r2=895628&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_error_codes.h (original)
+++ subversion/trunk/subversion/include/svn_error_codes.h Mon Jan  4 13:59:38 
2010
@@ -294,14 +294,9 @@
              "Stream doesn't support resetting")
 
   /** @since New in 1.7. */
-  SVN_ERRDEF(SVN_ERR_STREAM_MARK_NOT_SUPPORTED,
+  SVN_ERRDEF(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED,
              SVN_ERR_STREAM_CATEGORY_START + 4,
-             "Stream doesn't support marking")
-
-  /** @since New in 1.7. */
-  SVN_ERRDEF(SVN_ERR_STREAM_MARK_ALREADY_SET,
-             SVN_ERR_STREAM_CATEGORY_START + 5,
-             "Mark is already set on this stream")
+             "Stream doesn't support seeking")
 
   /* node errors */
 

Modified: subversion/trunk/subversion/include/svn_io.h
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/include/svn_io.h?rev=895628&r1=895627&r2=895628&view=diff
==============================================================================
--- subversion/trunk/subversion/include/svn_io.h (original)
+++ subversion/trunk/subversion/include/svn_io.h Mon Jan  4 13:59:38 2010
@@ -702,12 +702,29 @@
  */
 typedef svn_error_t *(*svn_io_reset_fn_t)(void *baton);
 
+/* An opaque type which represents a mark on a stream.
+ *
+ * @see svn_stream_mark().
+ * @since New in 1.7.
+ */
+typedef struct svn_stream_mark_t svn_stream_mark_t;
+
 /** Mark handler function for a generic stream. @see svn_stream_t and
  * svn_stream_mark().
  *
  * @since New in 1.7.
  */
-typedef svn_error_t *(*svn_io_mark_fn_t)(void *baton, svn_boolean_t set);
+typedef svn_error_t *(*svn_io_mark_fn_t)(void *baton,
+                                         svn_stream_mark_t **mark,
+                                         apr_pool_t *pool);
+
+/** Seek handler function for a generic stream. @see svn_stream_t and
+ * svn_stream_seek().
+ *
+ * @since New in 1.7.
+ */
+typedef svn_error_t *(*svn_io_seek_fn_t)(void *baton,
+                                         svn_stream_mark_t *mark);
 
 /** Line-filtering callback function for a generic stream.
  * @a baton is the stream's baton.
@@ -785,6 +802,14 @@
 svn_stream_set_mark(svn_stream_t *stream,
                     svn_io_mark_fn_t mark_fn);
 
+/** Set @a stream's seek function to @a seek_fn 
+ *
+ * @since New in 1.7.
+ */
+void
+svn_stream_set_seek(svn_stream_t *stream,
+                    svn_io_seek_fn_t seek_fn);
+
 /** Set @a stream's line-filtering callback function to @a line_filter_cb
  *
  * @since New in 1.7.
@@ -1046,27 +1071,35 @@
  * #SVN_ERR_STREAM_RESET_NOT_SUPPORTED error when the stream doesn't
  * implement resetting.
  *
- * If a mark has been set on the stream, the stream is reset to
- * the mark instead of its origin. @see svn_stream_mark()
- *
  * @since New in 1.7.
  */
 svn_error_t *
 svn_stream_reset(svn_stream_t *stream);
 
-/** Set or clear the mark on a generic stream according to @a set.
- * If @a set is TRUE, the mark is set at the current position in
- * the stream. If @a set is FALSE, the mark is cleared.
- * This function returns the #SVN_ERR_STREAM_MARK_NOT_SUPPORTED error
- * when the stream doesn't implement marking.
- * The error #SVN_ERR_STREAM_MARK_ALREADY_SET is returned if there was
- * an attempt to set a mark without clearing an existing mark beforehand.
+/** Set a @a mark at the current position of a generic @a stream,
+ * which can later be sought back to using svn_stream_seek().
+ * The @a mark is allocated in @a pool.
+ *
+ * This function returns the #SVN_ERR_STREAM_SEEK_NOT_SUPPORTED error
+ * if the stream doesn't implement seeking.
+ *
+ * @see svn_stream_seek()
+ * @since New in 1.7.
+ */
+svn_error_t *
+svn_stream_mark(svn_stream_t *stream,
+                svn_stream_mark_t **mark,
+                apr_pool_t *pool);
+
+/* Seek to a @a mark in a generic @a stream.
+ * This function returns the #SVN_ERR_STREAM_SEEK_NOT_SUPPORTED error
+ * if the stream doesn't implement seeking.
  *
- * @see svn_stream_reset()
+ * @see svn_stream_mark()
  * @since New in 1.7.
  */
 svn_error_t *
-svn_stream_mark(svn_stream_t *stream, svn_boolean_t set);
+svn_stream_seek(svn_stream_t *stream, svn_stream_mark_t *mark);
 
 /** Return a writable stream which, when written to, writes to both of the
  * underlying streams.  Both of these streams will be closed upon closure of

Modified: subversion/trunk/subversion/libsvn_subr/stream.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/libsvn_subr/stream.c?rev=895628&r1=895627&r2=895628&view=diff
==============================================================================
--- subversion/trunk/subversion/libsvn_subr/stream.c (original)
+++ subversion/trunk/subversion/libsvn_subr/stream.c Mon Jan  4 13:59:38 2010
@@ -52,10 +52,18 @@
   svn_close_fn_t close_fn;
   svn_io_reset_fn_t reset_fn;
   svn_io_mark_fn_t mark_fn;
+  svn_io_seek_fn_t seek_fn;
   svn_io_line_filter_cb_t line_filter_cb;
   svn_io_line_transformer_cb_t line_transformer_cb;
 };
 
+/* A type which represents a mark on a stream. */
+struct svn_stream_mark_t {
+  union {
+    apr_off_t apr;
+    apr_size_t stringbuf;
+  } m;
+};
 
 
 /*** Generic streams. ***/
@@ -72,6 +80,7 @@
   stream->close_fn = NULL;
   stream->reset_fn = NULL;
   stream->mark_fn = NULL;
+  stream->seek_fn = NULL;
   stream->line_filter_cb = NULL;
   stream->line_transformer_cb = NULL;
   return stream;
@@ -117,6 +126,12 @@
 }
 
 void
+svn_stream_set_seek(svn_stream_t *stream, svn_io_seek_fn_t seek_fn)
+{
+  stream->seek_fn = seek_fn;
+}
+
+void
 svn_stream_set_line_filter_callback(svn_stream_t *stream,
                                     svn_io_line_filter_cb_t line_filter_cb)
 {
@@ -157,12 +172,22 @@
 }
 
 svn_error_t *
-svn_stream_mark(svn_stream_t *stream, svn_boolean_t set)
+svn_stream_mark(svn_stream_t *stream, svn_stream_mark_t **mark,
+                apr_pool_t *pool)
 {
   if (stream->mark_fn == NULL)
-    return svn_error_create(SVN_ERR_STREAM_MARK_NOT_SUPPORTED, NULL, NULL);
+    return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED, NULL, NULL);
+
+  return stream->mark_fn(stream->baton, mark, pool);
+}
+
+svn_error_t *
+svn_stream_seek(svn_stream_t *stream, svn_stream_mark_t *mark)
+{
+  if (stream->seek_fn == NULL)
+    return svn_error_create(SVN_ERR_STREAM_SEEK_NOT_SUPPORTED, NULL, NULL);
 
-  return stream->mark_fn(stream->baton, set);
+  return stream->seek_fn(stream->baton, mark);
 }
 
 svn_error_t *
@@ -259,11 +284,12 @@
  * Set *EOL to NULL if the stream runs out before an end-of-line indicator
  * is found. */
 static svn_error_t *
-scan_eol(const char **eol, svn_stream_t *stream)
+scan_eol(const char **eol, svn_stream_t *stream, apr_pool_t *pool)
 {
   const char *eol_str;
+  svn_stream_mark_t *mark;
 
-  SVN_ERR(svn_stream_mark(stream, TRUE));
+  SVN_ERR(svn_stream_mark(stream, &mark, pool));
 
   eol_str = NULL;
   while (! eol_str)
@@ -278,8 +304,7 @@
       eol_str = svn_eol__detect_eol(buf, buf + len);
     }
 
-  SVN_ERR(svn_stream_reset(stream));
-  SVN_ERR(svn_stream_mark(stream, FALSE));
+  SVN_ERR(svn_stream_seek(stream, mark));
 
   *eol = eol_str;
 
@@ -324,7 +349,7 @@
 
       if (detect_eol)
         {
-          SVN_ERR(scan_eol(&eol_str, stream));
+          SVN_ERR(scan_eol(&eol_str, stream, iterpool));
           if (eol)
             *eol = eol_str;
           if (! eol_str)
@@ -500,11 +525,18 @@
 }
 
 static svn_error_t *
-mark_handler_empty(void *baton, svn_boolean_t set)
+mark_handler_empty(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool)
 {
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+seek_handler_empty(void *baton, svn_stream_mark_t *mark)
+{
+  return SVN_NO_ERROR;
+}
+
+
 svn_stream_t *
 svn_stream_empty(apr_pool_t *pool)
 {
@@ -515,6 +547,7 @@
   svn_stream_set_write(stream, write_handler_empty);
   svn_stream_set_reset(stream, reset_handler_empty);
   svn_stream_set_mark(stream, mark_handler_empty);
+  svn_stream_set_seek(stream, seek_handler_empty);
   return stream;
 }
 
@@ -598,9 +631,15 @@
 }
 
 static svn_error_t *
-mark_handler_disown(void *baton, svn_boolean_t set)
+mark_handler_disown(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool)
 {
-  return svn_stream_mark(baton, set);
+  return svn_stream_mark(baton, mark, pool);
+}
+
+static svn_error_t *
+seek_handler_disown(void *baton, svn_stream_mark_t *mark)
+{
+  return svn_stream_seek(baton, mark);
 }
 
 svn_stream_t *
@@ -612,6 +651,7 @@
   svn_stream_set_write(s, write_handler_disown);
   svn_stream_set_reset(s, reset_handler_disown);
   svn_stream_set_mark(s, mark_handler_disown);
+  svn_stream_set_seek(s, seek_handler_disown);
 
   return s;
 }
@@ -627,8 +667,6 @@
    * When either of these is negative, no range has been specified. */
   apr_off_t start;
   apr_off_t end;
-
-  apr_off_t mark;
 };
 
 
@@ -699,34 +737,30 @@
   apr_off_t offset;
   struct baton_apr *btn = baton;
 
-  if (btn->mark >= 0)
-    offset = btn->mark;
-  else if (btn->start >= 0)
-    offset = btn->start;
-  else
-    offset = 0;
+  /* If we're reading from a range, reset to the start of the range.
+   * Otherwise, reset to the start of the file. */
+  offset = btn->start >= 0 ? btn->start : 0;
 
   return svn_io_file_seek(btn->file, APR_SET, &offset, btn->pool);
 }
 
 static svn_error_t *
-mark_handler_apr(void *baton, svn_boolean_t set)
+mark_handler_apr(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool)
 {
   struct baton_apr *btn = baton;
-
-  if (set)
-    {
-      if (btn->mark != -1)
-        return svn_error_create(SVN_ERR_STREAM_MARK_ALREADY_SET, NULL, NULL);
-      btn->mark = 0;
-      SVN_ERR(svn_io_file_seek(btn->file, APR_CUR, &btn->mark, btn->pool));
-    }
-  else
-    btn->mark = -1;
-
+  (*mark) = apr_palloc(pool, sizeof(**mark));
+  (*mark)->m.apr = 0;
+  SVN_ERR(svn_io_file_seek(btn->file, APR_CUR, &(*mark)->m.apr, btn->pool));
   return SVN_NO_ERROR;
 }
 
+static svn_error_t *
+seek_handler_apr(void *baton, svn_stream_mark_t *mark)
+{
+  struct baton_apr *btn = baton;
+  SVN_ERR(svn_io_file_seek(btn->file, APR_SET, &mark->m.apr, btn->pool));
+  return SVN_NO_ERROR;
+}
 
 svn_error_t *
 svn_stream_open_readonly(svn_stream_t **stream,
@@ -799,12 +833,12 @@
   baton->pool = pool;
   baton->start = -1;
   baton->end = -1;
-  baton->mark = -1;
   stream = svn_stream_create(baton, pool);
   svn_stream_set_read(stream, read_handler_apr);
   svn_stream_set_write(stream, write_handler_apr);
   svn_stream_set_reset(stream, reset_handler_apr);
   svn_stream_set_mark(stream, mark_handler_apr);
+  svn_stream_set_seek(stream, seek_handler_apr);
 
   if (! disown)
     svn_stream_set_close(stream, close_handler_apr);
@@ -842,11 +876,11 @@
   baton->pool = pool;
   baton->start = start;
   baton->end = end;
-  baton->mark = -1;
   stream = svn_stream_create(baton, pool);
   svn_stream_set_read(stream, read_handler_apr);
   svn_stream_set_reset(stream, reset_handler_apr);
   svn_stream_set_mark(stream, mark_handler_apr);
+  svn_stream_set_seek(stream, seek_handler_apr);
 
   if (! disown)
     svn_stream_set_close(stream, close_handler_apr);
@@ -1344,7 +1378,6 @@
 {
   svn_stringbuf_t *str;
   apr_size_t amt_read;
-  apr_size_t mark;
 };
 
 static svn_error_t *
@@ -1372,25 +1405,24 @@
 reset_handler_stringbuf(void *baton)
 {
   struct stringbuf_stream_baton *btn = baton;
-  if (btn->mark != (apr_size_t)-1)
-    btn->amt_read = btn->mark;
-  else
-    btn->amt_read = 0;
+  btn->amt_read = 0;
   return SVN_NO_ERROR;
 }
 
 static svn_error_t *
-mark_handler_stringbuf(void *baton, svn_boolean_t set)
+mark_handler_stringbuf(void *baton, svn_stream_mark_t **mark, apr_pool_t *pool)
 {
   struct stringbuf_stream_baton *btn = baton;
-  if (set)
-    {
-      if (btn->mark != (apr_size_t)-1)
-        return svn_error_create(SVN_ERR_STREAM_MARK_ALREADY_SET, NULL, NULL);
-      btn->mark = btn->amt_read;
-    }
-  else
-    btn->mark = (apr_size_t)-1;
+  (*mark) = apr_palloc(pool, sizeof(**mark));
+  (*mark)->m.stringbuf = btn->amt_read;
+  return SVN_NO_ERROR;
+}
+
+static svn_error_t *
+seek_handler_stringbuf(void *baton, svn_stream_mark_t *mark)
+{
+  struct stringbuf_stream_baton *btn = baton;
+  btn->amt_read = mark->m.stringbuf;
   return SVN_NO_ERROR;
 }
 
@@ -1407,12 +1439,12 @@
   baton = apr_palloc(pool, sizeof(*baton));
   baton->str = str;
   baton->amt_read = 0;
-  baton->mark = (apr_size_t)-1;
   stream = svn_stream_create(baton, pool);
   svn_stream_set_read(stream, read_handler_stringbuf);
   svn_stream_set_write(stream, write_handler_stringbuf);
   svn_stream_set_reset(stream, reset_handler_stringbuf);
   svn_stream_set_mark(stream, mark_handler_stringbuf);
+  svn_stream_set_seek(stream, seek_handler_stringbuf);
   return stream;
 }
 

Modified: subversion/trunk/subversion/tests/libsvn_subr/stream-test.c
URL: 
http://svn.apache.org/viewvc/subversion/trunk/subversion/tests/libsvn_subr/stream-test.c?rev=895628&r1=895627&r2=895628&view=diff
==============================================================================
--- subversion/trunk/subversion/tests/libsvn_subr/stream-test.c (original)
+++ subversion/trunk/subversion/tests/libsvn_subr/stream-test.c Mon Jan  4 
13:59:38 2010
@@ -465,17 +465,18 @@
 }
 
 static svn_error_t *
-test_stream_mark_file(apr_pool_t *pool)
+test_stream_seek_file(apr_pool_t *pool)
 {
   static const char *file_data[2] = {"One", "Two"};
   svn_stream_t *stream;
   svn_stringbuf_t *line;
   svn_boolean_t eof;
   apr_file_t *f;
-  static const char *fname = "test_stream_mark.txt";
+  static const char *fname = "test_stream_seek.txt";
   int j;
   apr_status_t status;
   static const char *NL = APR_EOL_STR;
+  svn_stream_mark_t *mark;
 
   status = apr_file_open(&f, fname, (APR_READ | APR_WRITE | APR_CREATE |
                          APR_TRUNCATE | APR_DELONCLOSE), APR_OS_DEFAULT, pool);
@@ -506,24 +507,17 @@
   SVN_ERR(svn_stream_readline(stream, &line, NL, &eof, pool));
   SVN_ERR_ASSERT(! eof && strcmp(line->data, file_data[0]) == 0);
   /* Set a mark at the beginning of the second line of the file. */
-  SVN_ERR(svn_stream_mark(stream, TRUE));
-  /* Read the second line and then reset the stream. */
+  SVN_ERR(svn_stream_mark(stream, &mark, pool));
+  /* Read the second line and then seek back to the mark. */
   SVN_ERR(svn_stream_readline(stream, &line, NL, &eof, pool));
   SVN_ERR_ASSERT(! eof && strcmp(line->data, file_data[1]) == 0);
-  SVN_ERR(svn_stream_reset(stream));
+  SVN_ERR(svn_stream_seek(stream, mark));
   /* The next read should return the second line again. */
   SVN_ERR(svn_stream_readline(stream, &line, NL, &eof, pool));
   SVN_ERR_ASSERT(! eof && strcmp(line->data, file_data[1]) == 0);
-  /* Clear the mark. */
-  SVN_ERR(svn_stream_mark(stream, FALSE));
   /* The next read should return EOF. */
   SVN_ERR(svn_stream_readline(stream, &line, NL, &eof, pool));
   SVN_ERR_ASSERT(eof);
-  /* Reset the stream. */
-  SVN_ERR(svn_stream_reset(stream));
-  /* The next read should return the first line again. */
-  SVN_ERR(svn_stream_readline(stream, &line, NL, &eof, pool));
-  SVN_ERR_ASSERT(! eof && strcmp(line->data, file_data[0]) == 0);
 
   SVN_ERR(svn_stream_close(stream));
 
@@ -531,12 +525,13 @@
 }
 
 static svn_error_t *
-test_stream_mark_stringbuf(apr_pool_t *pool)
+test_stream_seek_stringbuf(apr_pool_t *pool)
 {
   svn_stream_t *stream;
   svn_stringbuf_t *stringbuf;
   char buf[4];
   apr_size_t len;
+  svn_stream_mark_t *mark;
 
   stringbuf = svn_stringbuf_create("OneTwo", pool);
   stream = svn_stream_from_stringbuf(stringbuf, pool);
@@ -544,22 +539,16 @@
   SVN_ERR(svn_stream_read(stream, buf, &len));
   buf[3] = '\0';
   SVN_ERR_ASSERT(strcmp(buf, "One") == 0);
-  SVN_ERR(svn_stream_mark(stream, TRUE));
+  SVN_ERR(svn_stream_mark(stream, &mark, pool));
   len = 3;
   SVN_ERR(svn_stream_read(stream, buf, &len));
   buf[3] = '\0';
   SVN_ERR_ASSERT(strcmp(buf, "Two") == 0);
-  SVN_ERR(svn_stream_reset(stream));
+  SVN_ERR(svn_stream_seek(stream, mark));
   len = 3;
   SVN_ERR(svn_stream_read(stream, buf, &len));
   buf[3] = '\0';
   SVN_ERR_ASSERT(strcmp(buf, "Two") == 0);
-  SVN_ERR(svn_stream_mark(stream, FALSE));
-  SVN_ERR(svn_stream_reset(stream));
-  len = 3;
-  SVN_ERR(svn_stream_read(stream, buf, &len));
-  buf[3] = '\0';
-  SVN_ERR_ASSERT(strcmp(buf, "One") == 0);
 
   SVN_ERR(svn_stream_close(stream));
 
@@ -586,9 +575,9 @@
                    "test stream line filtering and transforming"),
     SVN_TEST_PASS2(test_stream_tee,
                    "test 'tee' streams"),
-    SVN_TEST_PASS2(test_stream_mark_file,
-                   "test stream marking for files"),
-    SVN_TEST_PASS2(test_stream_mark_stringbuf,
-                   "test stream marking for stringbufs"),
+    SVN_TEST_PASS2(test_stream_seek_file,
+                   "test stream seeking for files"),
+    SVN_TEST_PASS2(test_stream_seek_stringbuf,
+                   "test stream seeking for stringbufs"),
     SVN_TEST_NULL
   };


Reply via email to