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 <jrnieder@gmail.com>
Jonathan Nieder committed
Oct 10, 2010 at 21:41 UTC
e5e45ca1e35482d120a7ce776cf208369edcc459
7 files changed
+50
-46
test-line-buffer.c
+9
-8
@@ -22,25 +22,26 @@ static uint32_t strtouint32(const char *s)
22
23
int main(int argc, char *argv[])
24
{
25
+ struct line_buffer buf = LINE_BUFFER_INIT;
26
char *s;
27
28
if (argc != 1)
29
usage("test-line-buffer < input.txt");
29
- if (buffer_init(NULL))
30
+ if (buffer_init(&buf, NULL))
31
die_errno("open error");
31
- while ((s = buffer_read_line())) {
32
- s = buffer_read_string(strtouint32(s));
32
+ while ((s = buffer_read_line(&buf))) {
33
+ s = buffer_read_string(&buf, strtouint32(s));
34
fputs(s, stdout);
35
fputc('\n', stdout);
35
- buffer_skip_bytes(1);
36
- if (!(s = buffer_read_line()))
36
+ buffer_skip_bytes(&buf, 1);
37
+ if (!(s = buffer_read_line(&buf)))
38
break;
38
- buffer_copy_bytes(strtouint32(s) + 1);
39
+ buffer_copy_bytes(&buf, strtouint32(s) + 1);
40
}
40
- if (buffer_deinit())
41
+ if (buffer_deinit(&buf))
42
die("input error");
43
if (ferror(stdout))
44
die("output error");
44
- buffer_reset();
45
+ buffer_reset(&buf);
46
return 0;
47
}
vcs-svn/fast_export.c
+3
-3
@@ -63,14 +63,14 @@ void fast_export_commit(uint32_t revision, uint32_t author, char *log,
63
printf("progress Imported commit %"PRIu32".\n\n", revision);
64
}
65
66
-void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len)
66
+void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len, struct line_buffer *input)
67
{
68
if (mode == REPO_MODE_LNK) {
69
/* svn symlink blobs start with "link " */
70
- buffer_skip_bytes(5);
70
+ buffer_skip_bytes(input, 5);
71
len -= 5;
72
}
73
printf("blob\nmark :%"PRIu32"\ndata %"PRIu32"\n", mark, len);
74
- buffer_copy_bytes(len);
74
+ buffer_copy_bytes(input, len);
75
fputc('\n', stdout);
76
}
vcs-svn/fast_export.h
+4
-1
@@ -1,11 +1,14 @@
1
#ifndef FAST_EXPORT_H_
2
#define FAST_EXPORT_H_
3
4
+#include "line_buffer.h"
5
+
6
void fast_export_delete(uint32_t depth, uint32_t *path);
7
void fast_export_modify(uint32_t depth, uint32_t *path, uint32_t mode,
8
uint32_t mark);
9
void fast_export_commit(uint32_t revision, uint32_t author, char *log,
10
uint32_t uuid, uint32_t url, unsigned long timestamp);
9
-void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len);
11
+void fast_export_blob(uint32_t mode, uint32_t mark, uint32_t len,
12
+ struct line_buffer *input);
13
14
#endif
vcs-svn/line_buffer.c
+8
-12
@@ -8,20 +8,16 @@
8
#include "strbuf.h"
9
10
#define COPY_BUFFER_LEN 4096
11
-static struct line_buffer buf_ = LINE_BUFFER_INIT;
12
-static struct line_buffer *buf;
11
14
-int buffer_init(const char *filename)
12
+int buffer_init(struct line_buffer *buf, const char *filename)
13
{
16
- buf = &buf_;
17
-
14
buf->infile = filename ? fopen(filename, "r") : stdin;
15
if (!buf->infile)
16
return -1;
17
return 0;
18
}
19
24
-int buffer_deinit(void)
20
+int buffer_deinit(struct line_buffer *buf)
21
{
22
int err;
23
if (buf->infile == stdin)
@@ -32,7 +28,7 @@ int buffer_deinit(void)
28
}
29
30
/* Read a line without trailing newline. */
35
-char *buffer_read_line(void)
31
+char *buffer_read_line(struct line_buffer *buf)
32
{
33
char *end;
34
if (!fgets(buf->line_buffer, sizeof(buf->line_buffer), buf->infile))
@@ -53,14 +49,14 @@ char *buffer_read_line(void)
49
return buf->line_buffer;
50
}
51
56
-char *buffer_read_string(uint32_t len)
52
+char *buffer_read_string(struct line_buffer *buf, uint32_t len)
53
{
54
strbuf_reset(&buf->blob_buffer);
55
strbuf_fread(&buf->blob_buffer, len, buf->infile);
56
return ferror(buf->infile) ? NULL : buf->blob_buffer.buf;
57
}
58
63
-void buffer_copy_bytes(uint32_t len)
59
+void buffer_copy_bytes(struct line_buffer *buf, uint32_t len)
60
{
61
char byte_buffer[COPY_BUFFER_LEN];
62
uint32_t in;
@@ -70,13 +66,13 @@ void buffer_copy_bytes(uint32_t len)
66
len -= in;
67
fwrite(byte_buffer, 1, in, stdout);
68
if (ferror(stdout)) {
73
- buffer_skip_bytes(len);
69
+ buffer_skip_bytes(buf, len);
70
return;
71
}
72
}
73
}
74
79
-void buffer_skip_bytes(uint32_t len)
75
+void buffer_skip_bytes(struct line_buffer *buf, uint32_t len)
76
{
77
char byte_buffer[COPY_BUFFER_LEN];
78
uint32_t in;
@@ -87,7 +83,7 @@ void buffer_skip_bytes(uint32_t len)
83
}
84
}
85
90
-void buffer_reset(void)
86
+void buffer_reset(struct line_buffer *buf)
87
{
88
strbuf_release(&buf->blob_buffer);
89
}
vcs-svn/line_buffer.h
+7
-7
@@ -12,12 +12,12 @@ struct line_buffer {
12
};
13
#define LINE_BUFFER_INIT {"", STRBUF_INIT, NULL}
14
15
-int buffer_init(const char *filename);
16
-int buffer_deinit(void);
17
-char *buffer_read_line(void);
18
-char *buffer_read_string(uint32_t len);
19
-void buffer_copy_bytes(uint32_t len);
20
-void buffer_skip_bytes(uint32_t len);
21
-void buffer_reset(void);
15
+int buffer_init(struct line_buffer *buf, const char *filename);
16
+int buffer_deinit(struct line_buffer *buf);
17
+char *buffer_read_line(struct line_buffer *buf);
18
+char *buffer_read_string(struct line_buffer *buf, uint32_t len);
19
+void buffer_copy_bytes(struct line_buffer *buf, uint32_t len);
20
+void buffer_skip_bytes(struct line_buffer *buf, uint32_t len);
21
+void buffer_reset(struct line_buffer *buf);
22
23
#endif
vcs-svn/line_buffer.txt
+3
-2
@@ -14,14 +14,15 @@ Calling sequence
14
15
The calling program:
16
17
+ - initializes a `struct line_buffer` to LINE_BUFFER_INIT
18
- specifies a file to read with `buffer_init`
19
- processes input with `buffer_read_line`, `buffer_read_string`,
20
`buffer_skip_bytes`, and `buffer_copy_bytes`
21
- closes the file with `buffer_deinit`, perhaps to start over and
22
read another file.
23
23
-Before exiting, the caller can use `buffer_reset` to deallocate
24
-resources for the benefit of profiling tools.
24
+When finished, the caller can use `buffer_reset` to deallocate
25
+resources.
26
27
Functions
28
---------
vcs-svn/svndump.c
+16
-13
@@ -30,6 +30,8 @@
30
/* Create memory pool for log messages */
31
obj_pool_gen(log, char, 4096)
32
33
+static struct line_buffer input = LINE_BUFFER_INIT;
34
+
35
static char* log_copy(uint32_t length, char *log)
36
{
37
char *buffer;
@@ -115,14 +117,14 @@ static void read_props(void)
117
uint32_t key = ~0;
118
char *val = NULL;
119
char *t;
118
- while ((t = buffer_read_line()) && strcmp(t, "PROPS-END")) {
120
+ while ((t = buffer_read_line(&input)) && strcmp(t, "PROPS-END")) {
121
if (!strncmp(t, "K ", 2)) {
122
len = atoi(&t[2]);
121
- key = pool_intern(buffer_read_string(len));
122
- buffer_read_line();
123
+ key = pool_intern(buffer_read_string(&input, len));
124
+ buffer_read_line(&input);
125
} else if (!strncmp(t, "V ", 2)) {
126
len = atoi(&t[2]);
125
- val = buffer_read_string(len);
127
+ val = buffer_read_string(&input, len);
128
if (key == keys.svn_log) {
129
/* Value length excludes terminating nul. */
130
rev_ctx.log = log_copy(len + 1, val);
@@ -137,7 +139,7 @@ static void read_props(void)
139
node_ctx.type = REPO_MODE_LNK;
140
}
141
key = ~0;
140
- buffer_read_line();
142
+ buffer_read_line(&input);
143
}
144
}
145
}
@@ -179,9 +181,10 @@ static void handle_node(void)
181
node_ctx.type = node_ctx.srcMode;
182
183
if (node_ctx.mark)
182
- fast_export_blob(node_ctx.type, node_ctx.mark, node_ctx.textLength);
184
+ fast_export_blob(node_ctx.type,
185
+ node_ctx.mark, node_ctx.textLength, &input);
186
else if (node_ctx.textLength != LENGTH_UNKNOWN)
184
- buffer_skip_bytes(node_ctx.textLength);
187
+ buffer_skip_bytes(&input, node_ctx.textLength);
188
}
189
190
static void handle_revision(void)
@@ -200,7 +203,7 @@ void svndump_read(const char *url)
203
uint32_t key;
204
205
reset_dump_ctx(pool_intern(url));
203
- while ((t = buffer_read_line())) {
206
+ while ((t = buffer_read_line(&input))) {
207
val = strstr(t, ": ");
208
if (!val)
209
continue;
@@ -257,7 +260,7 @@ void svndump_read(const char *url)
260
node_ctx.propLength = atoi(val);
261
} else if (key == keys.content_length) {
262
len = atoi(val);
260
- buffer_read_line();
263
+ buffer_read_line(&input);
264
if (active_ctx == REV_CTX) {
265
read_props();
266
} else if (active_ctx == NODE_CTX) {
@@ -265,7 +268,7 @@ void svndump_read(const char *url)
268
active_ctx = REV_CTX;
269
} else {
270
fprintf(stderr, "Unexpected content length header: %"PRIu32"\n", len);
268
- buffer_skip_bytes(len);
271
+ buffer_skip_bytes(&input, len);
272
}
273
}
274
}
@@ -277,7 +280,7 @@ void svndump_read(const char *url)
280
281
void svndump_init(const char *filename)
282
{
280
- buffer_init(filename);
283
+ buffer_init(&input, filename);
284
repo_init();
285
reset_dump_ctx(~0);
286
reset_rev_ctx(0);
@@ -292,7 +295,7 @@ void svndump_deinit(void)
295
reset_dump_ctx(~0);
296
reset_rev_ctx(0);
297
reset_node_ctx(NULL);
295
- if (buffer_deinit())
298
+ if (buffer_deinit(&input))
299
fprintf(stderr, "Input error\n");
300
if (ferror(stdout))
301
fprintf(stderr, "Output error\n");
@@ -301,7 +304,7 @@ void svndump_deinit(void)
304
void svndump_reset(void)
305
{
306
log_reset();
304
- buffer_reset();
307
+ buffer_reset(&input);
308
repo_reset();
309
reset_dump_ctx(~0);
310
reset_rev_ctx(0);