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