git-commit-vandalism/vcs-svn/line_buffer.c
Jonathan Nieder b1c9b798a6 vcs-svn: teach line_buffer about temporary files
It can sometimes be useful to write information temporarily to file,
to read back later.  These functions allow a program to use the
line_buffer facilities when doing so.

It works like this:

 1. find a unique filename with buffer_tmpfile_init.
 2. rewind with buffer_tmpfile_rewind.  This returns a stdio
    handle for writing.
 3. when finished writing, declare so with
    buffer_tmpfile_prepare_to_read.  The return value indicates
    how many bytes were written.
 4. read whatever portion of the file is needed.
 5. if finished, remove the temporary file with buffer_deinit.
    otherwise, go back to step 2,

The svn support would use this to buffer the postimage from delta
application until the length is known and fast-import can receive
the resulting blob.

Based-on-patch-by: David Barr <david.barr@cordelta.com>
Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
2011-02-26 04:59:37 -06:00

133 lines
2.9 KiB
C

/*
* Licensed under a two-clause BSD-style license.
* See LICENSE for details.
*/
#include "git-compat-util.h"
#include "line_buffer.h"
#include "strbuf.h"
#define COPY_BUFFER_LEN 4096
int buffer_init(struct line_buffer *buf, const char *filename)
{
buf->infile = filename ? fopen(filename, "r") : stdin;
if (!buf->infile)
return -1;
return 0;
}
int buffer_fdinit(struct line_buffer *buf, int fd)
{
buf->infile = fdopen(fd, "r");
if (!buf->infile)
return -1;
return 0;
}
int buffer_tmpfile_init(struct line_buffer *buf)
{
buf->infile = tmpfile();
if (!buf->infile)
return -1;
return 0;
}
int buffer_deinit(struct line_buffer *buf)
{
int err;
if (buf->infile == stdin)
return ferror(buf->infile);
err = ferror(buf->infile);
err |= fclose(buf->infile);
return err;
}
FILE *buffer_tmpfile_rewind(struct line_buffer *buf)
{
rewind(buf->infile);
return buf->infile;
}
long buffer_tmpfile_prepare_to_read(struct line_buffer *buf)
{
long pos = ftell(buf->infile);
if (pos < 0)
return error("ftell error: %s", strerror(errno));
if (fseek(buf->infile, 0, SEEK_SET))
return error("seek error: %s", strerror(errno));
return pos;
}
int buffer_read_char(struct line_buffer *buf)
{
return fgetc(buf->infile);
}
/* Read a line without trailing newline. */
char *buffer_read_line(struct line_buffer *buf)
{
char *end;
if (!fgets(buf->line_buffer, sizeof(buf->line_buffer), buf->infile))
/* Error or data exhausted. */
return NULL;
end = buf->line_buffer + strlen(buf->line_buffer);
if (end[-1] == '\n')
end[-1] = '\0';
else if (feof(buf->infile))
; /* No newline at end of file. That's fine. */
else
/*
* Line was too long.
* There is probably a saner way to deal with this,
* but for now let's return an error.
*/
return NULL;
return buf->line_buffer;
}
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_read_binary(struct line_buffer *buf,
struct strbuf *sb, uint32_t size)
{
strbuf_fread(sb, size, buf->infile);
}
void buffer_copy_bytes(struct line_buffer *buf, uint32_t len)
{
char byte_buffer[COPY_BUFFER_LEN];
uint32_t in;
while (len > 0 && !feof(buf->infile) && !ferror(buf->infile)) {
in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN;
in = fread(byte_buffer, 1, in, buf->infile);
len -= in;
fwrite(byte_buffer, 1, in, stdout);
if (ferror(stdout)) {
buffer_skip_bytes(buf, len);
return;
}
}
}
void buffer_skip_bytes(struct line_buffer *buf, uint32_t len)
{
char byte_buffer[COPY_BUFFER_LEN];
uint32_t in;
while (len > 0 && !feof(buf->infile) && !ferror(buf->infile)) {
in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN;
in = fread(byte_buffer, 1, in, buf->infile);
len -= in;
}
}
void buffer_reset(struct line_buffer *buf)
{
strbuf_release(&buf->blob_buffer);
}