vcs-svn: teach line_buffer to handle multiple input files
authorJonathan Nieder <jrnieder@gmail.com>
Mon, 11 Oct 2010 02:41:06 +0000 (21:41 -0500)
committerJonathan Nieder <jrnieder@gmail.com>
Sat, 26 Feb 2011 10:57:59 +0000 (04:57 -0600)
Collect the line_buffer state in a newly public line_buffer struct.
Callers can use multiple line_buffers to manage input from multiple
files at a time.

svn-fe's delta applier will use this to stream a delta from svnrdump
and the preimage it applies to from fast-import at the same time.

The tests don't take advantage of the new features, but I think that's
okay.  It is easier to find lingering examples of nonreentrant code by
searching for "static" in line_buffer.c.

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
test-line-buffer.c
vcs-svn/fast_export.c
vcs-svn/fast_export.h
vcs-svn/line_buffer.c
vcs-svn/line_buffer.h
vcs-svn/line_buffer.txt
vcs-svn/svndump.c

index c11bf7f96708c90c992423fc27b2eba73d0c34a0..f9af892d28efce4dbbf5aef812917c380a672b17 100644 (file)
@@ -22,25 +22,26 @@ static uint32_t strtouint32(const char *s)
 
 int main(int argc, char *argv[])
 {
+       struct line_buffer buf = LINE_BUFFER_INIT;
        char *s;
 
        if (argc != 1)
                usage("test-line-buffer < input.txt");
-       if (buffer_init(NULL))
+       if (buffer_init(&buf, NULL))
                die_errno("open error");
-       while ((s = buffer_read_line())) {
-               s = buffer_read_string(strtouint32(s));
+       while ((s = buffer_read_line(&buf))) {
+               s = buffer_read_string(&buf, strtouint32(s));
                fputs(s, stdout);
                fputc('\n', stdout);
-               buffer_skip_bytes(1);
-               if (!(s = buffer_read_line()))
+               buffer_skip_bytes(&buf, 1);
+               if (!(s = buffer_read_line(&buf)))
                        break;
-               buffer_copy_bytes(strtouint32(s) + 1);
+               buffer_copy_bytes(&buf, strtouint32(s) + 1);
        }
-       if (buffer_deinit())
+       if (buffer_deinit(&buf))
                die("input error");
        if (ferror(stdout))
                die("output error");
-       buffer_reset();
+       buffer_reset(&buf);
        return 0;
 }
index 6cfa256a3702332205faab546a405f6810cc16bd..260cf50e7725c9199fa44134a7f3408da7cad984 100644 (file)
@@ -63,14 +63,14 @@ void fast_export_commit(uint32_t revision, uint32_t author, char *log,
        printf("progress Imported commit %"PRIu32".\n\n", revision);
 }
 
-void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len)
+void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len, struct line_buffer *input)
 {
        if (mode == REPO_MODE_LNK) {
                /* svn symlink blobs start with "link " */
-               buffer_skip_bytes(5);
+               buffer_skip_bytes(input, 5);
                len -= 5;
        }
        printf("blob\nmark :%"PRIu32"\ndata %"PRIu32"\n", mark, len);
-       buffer_copy_bytes(len);
+       buffer_copy_bytes(input, len);
        fputc('\n', stdout);
 }
index 2aaaea53d57bcc6a5280765dd39edf7fc5569c19..054e7d5eb1aeb4b2808acc0360e6371a376d40f7 100644 (file)
@@ -1,11 +1,14 @@
 #ifndef FAST_EXPORT_H_
 #define FAST_EXPORT_H_
 
+#include "line_buffer.h"
+
 void fast_export_delete(uint32_t depth, uint32_t *path);
 void fast_export_modify(uint32_t depth, uint32_t *path, uint32_t mode,
                        uint32_t mark);
 void fast_export_commit(uint32_t revision, uint32_t author, char *log,
                        uint32_t uuid, uint32_t url, unsigned long timestamp);
-void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len);
+void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len,
+                     struct line_buffer *input);
 
 #endif
index e7bc230fcbf5dc021e8a5e8aa6f9ec66ce06ad6d..806932b32187bece9076131c69e8f80ae0c3a58a 100644 (file)
@@ -8,20 +8,16 @@
 #include "strbuf.h"
 
 #define COPY_BUFFER_LEN 4096
-static struct line_buffer buf_ = LINE_BUFFER_INIT;
-static struct line_buffer *buf;
 
-int buffer_init(const char *filename)
+int buffer_init(struct line_buffer *buf, const char *filename)
 {
-       buf = &buf_;
-
        buf->infile = filename ? fopen(filename, "r") : stdin;
        if (!buf->infile)
                return -1;
        return 0;
 }
 
-int buffer_deinit(void)
+int buffer_deinit(struct line_buffer *buf)
 {
        int err;
        if (buf->infile == stdin)
@@ -32,7 +28,7 @@ int buffer_deinit(void)
 }
 
 /* Read a line without trailing newline. */
-char *buffer_read_line(void)
+char *buffer_read_line(struct line_buffer *buf)
 {
        char *end;
        if (!fgets(buf->line_buffer, sizeof(buf->line_buffer), buf->infile))
@@ -53,14 +49,14 @@ char *buffer_read_line(void)
        return buf->line_buffer;
 }
 
-char *buffer_read_string(uint32_t len)
+char *buffer_read_string(struct line_buffer *buf, uint32_t len)
 {
        strbuf_reset(&buf->blob_buffer);
        strbuf_fread(&buf->blob_buffer, len, buf->infile);
        return ferror(buf->infile) ? NULL : buf->blob_buffer.buf;
 }
 
-void buffer_copy_bytes(uint32_t len)
+void buffer_copy_bytes(struct line_buffer *buf, uint32_t len)
 {
        char byte_buffer[COPY_BUFFER_LEN];
        uint32_t in;
@@ -70,13 +66,13 @@ void buffer_copy_bytes(uint32_t len)
                len -= in;
                fwrite(byte_buffer, 1, in, stdout);
                if (ferror(stdout)) {
-                       buffer_skip_bytes(len);
+                       buffer_skip_bytes(buf, len);
                        return;
                }
        }
 }
 
-void buffer_skip_bytes(uint32_t len)
+void buffer_skip_bytes(struct line_buffer *buf, uint32_t len)
 {
        char byte_buffer[COPY_BUFFER_LEN];
        uint32_t in;
@@ -87,7 +83,7 @@ void buffer_skip_bytes(uint32_t len)
        }
 }
 
-void buffer_reset(void)
+void buffer_reset(struct line_buffer *buf)
 {
        strbuf_release(&buf->blob_buffer);
 }
index 4ae1133a92993f6cc205f873adf8a8860f992909..fb373903d20318da44ddc784842c56521b41e141 100644 (file)
@@ -12,12 +12,12 @@ struct line_buffer {
 };
 #define LINE_BUFFER_INIT {"", STRBUF_INIT, NULL}
 
-int buffer_init(const char *filename);
-int buffer_deinit(void);
-char *buffer_read_line(void);
-char *buffer_read_string(uint32_t len);
-void buffer_copy_bytes(uint32_t len);
-void buffer_skip_bytes(uint32_t len);
-void buffer_reset(void);
+int buffer_init(struct line_buffer *buf, const char *filename);
+int buffer_deinit(struct line_buffer *buf);
+char *buffer_read_line(struct line_buffer *buf);
+char *buffer_read_string(struct line_buffer *buf, uint32_t len);
+void buffer_copy_bytes(struct line_buffer *buf, uint32_t len);
+void buffer_skip_bytes(struct line_buffer *buf, uint32_t len);
+void buffer_reset(struct line_buffer *buf);
 
 #endif
index 8906fb1f505e125ea58fd7a15c4f13bb0dc78f27..f8eaa4dd8c2508c6e0c5b9b46649dc7232e50116 100644 (file)
@@ -14,14 +14,15 @@ Calling sequence
 
 The calling program:
 
+ - initializes a `struct line_buffer` to LINE_BUFFER_INIT
  - specifies a file to read with `buffer_init`
  - processes input with `buffer_read_line`, `buffer_read_string`,
    `buffer_skip_bytes`, and `buffer_copy_bytes`
  - closes the file with `buffer_deinit`, perhaps to start over and
    read another file.
 
-Before exiting, the caller can use `buffer_reset` to deallocate
-resources for the benefit of profiling tools.
+When finished, the caller can use `buffer_reset` to deallocate
+resources.
 
 Functions
 ---------
index 2ad2c307dd6e8f4bddf5cbd9c588973a085bf870..4195da9cf8000ec3e01fcaa6c1564188497b862b 100644 (file)
@@ -30,6 +30,8 @@
 /* Create memory pool for log messages */
 obj_pool_gen(log, char, 4096)
 
+static struct line_buffer input = LINE_BUFFER_INIT;
+
 static char* log_copy(uint32_t length, char *log)
 {
        char *buffer;
@@ -115,14 +117,14 @@ static void read_props(void)
        uint32_t key = ~0;
        char *val = NULL;
        char *t;
-       while ((t = buffer_read_line()) && strcmp(t, "PROPS-END")) {
+       while ((t = buffer_read_line(&input)) && strcmp(t, "PROPS-END")) {
                if (!strncmp(t, "K ", 2)) {
                        len = atoi(&t[2]);
-                       key = pool_intern(buffer_read_string(len));
-                       buffer_read_line();
+                       key = pool_intern(buffer_read_string(&input, len));
+                       buffer_read_line(&input);
                } else if (!strncmp(t, "V ", 2)) {
                        len = atoi(&t[2]);
-                       val = buffer_read_string(len);
+                       val = buffer_read_string(&input, len);
                        if (key == keys.svn_log) {
                                /* Value length excludes terminating nul. */
                                rev_ctx.log = log_copy(len + 1, val);
@@ -137,7 +139,7 @@ static void read_props(void)
                                node_ctx.type = REPO_MODE_LNK;
                        }
                        key = ~0;
-                       buffer_read_line();
+                       buffer_read_line(&input);
                }
        }
 }
@@ -179,9 +181,10 @@ static void handle_node(void)
                node_ctx.type = node_ctx.srcMode;
 
        if (node_ctx.mark)
-               fast_export_blob(node_ctx.type, node_ctx.mark, node_ctx.textLength);
+               fast_export_blob(node_ctx.type,
+                                node_ctx.mark, node_ctx.textLength, &input);
        else if (node_ctx.textLength != LENGTH_UNKNOWN)
-               buffer_skip_bytes(node_ctx.textLength);
+               buffer_skip_bytes(&input, node_ctx.textLength);
 }
 
 static void handle_revision(void)
@@ -200,7 +203,7 @@ void svndump_read(const char *url)
        uint32_t key;
 
        reset_dump_ctx(pool_intern(url));
-       while ((t = buffer_read_line())) {
+       while ((t = buffer_read_line(&input))) {
                val = strstr(t, ": ");
                if (!val)
                        continue;
@@ -257,7 +260,7 @@ void svndump_read(const char *url)
                        node_ctx.propLength = atoi(val);
                } else if (key == keys.content_length) {
                        len = atoi(val);
-                       buffer_read_line();
+                       buffer_read_line(&input);
                        if (active_ctx == REV_CTX) {
                                read_props();
                        } else if (active_ctx == NODE_CTX) {
@@ -265,7 +268,7 @@ void svndump_read(const char *url)
                                active_ctx = REV_CTX;
                        } else {
                                fprintf(stderr, "Unexpected content length header: %"PRIu32"\n", len);
-                               buffer_skip_bytes(len);
+                               buffer_skip_bytes(&input, len);
                        }
                }
        }
@@ -277,7 +280,7 @@ void svndump_read(const char *url)
 
 void svndump_init(const char *filename)
 {
-       buffer_init(filename);
+       buffer_init(&input, filename);
        repo_init();
        reset_dump_ctx(~0);
        reset_rev_ctx(0);
@@ -292,7 +295,7 @@ void svndump_deinit(void)
        reset_dump_ctx(~0);
        reset_rev_ctx(0);
        reset_node_ctx(NULL);
-       if (buffer_deinit())
+       if (buffer_deinit(&input))
                fprintf(stderr, "Input error\n");
        if (ferror(stdout))
                fprintf(stderr, "Output error\n");
@@ -301,7 +304,7 @@ void svndump_deinit(void)
 void svndump_reset(void)
 {
        log_reset();
-       buffer_reset();
+       buffer_reset(&input);
        repo_reset();
        reset_dump_ctx(~0);
        reset_rev_ctx(0);