From e5e45ca1e35482d120a7ce776cf208369edcc459 Mon Sep 17 00:00:00 2001 From: Jonathan Nieder Date: Sun, 10 Oct 2010 21:41:06 -0500 Subject: vcs-svn: teach line_buffer to handle multiple input files 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 diff --git a/test-line-buffer.c b/test-line-buffer.c index c11bf7f..f9af892 100644 --- a/test-line-buffer.c +++ b/test-line-buffer.c @@ -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; } diff --git a/vcs-svn/fast_export.c b/vcs-svn/fast_export.c index 6cfa256..260cf50 100644 --- a/vcs-svn/fast_export.c +++ b/vcs-svn/fast_export.c @@ -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); } diff --git a/vcs-svn/fast_export.h b/vcs-svn/fast_export.h index 2aaaea5..054e7d5 100644 --- a/vcs-svn/fast_export.h +++ b/vcs-svn/fast_export.h @@ -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 diff --git a/vcs-svn/line_buffer.c b/vcs-svn/line_buffer.c index e7bc230..806932b 100644 --- a/vcs-svn/line_buffer.c +++ b/vcs-svn/line_buffer.c @@ -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); } diff --git a/vcs-svn/line_buffer.h b/vcs-svn/line_buffer.h index 4ae1133..fb37390 100644 --- a/vcs-svn/line_buffer.h +++ b/vcs-svn/line_buffer.h @@ -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 diff --git a/vcs-svn/line_buffer.txt b/vcs-svn/line_buffer.txt index 8906fb1..f8eaa4d 100644 --- a/vcs-svn/line_buffer.txt +++ b/vcs-svn/line_buffer.txt @@ -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 --------- diff --git a/vcs-svn/svndump.c b/vcs-svn/svndump.c index 2ad2c30..4195da9 100644 --- a/vcs-svn/svndump.c +++ b/vcs-svn/svndump.c @@ -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); -- cgit v0.10.2-6-g49f6