git/vcs-svn/line_buffer.c
Jonathan Nieder cc193f1f0b vcs-svn: allow character-oriented input
buffer_read_char can be used in place of buffer_read_string(1) to
avoid consuming valuable static buffer space.  The delta applier will
use this to read variable-length integers one byte at a time.

Underneath, it is fgetc, wrapped so the line_buffer library can
maintain its role as gatekeeper of input.

Later it might be worth checking if fgetc_unlocked is faster ---
most line_buffer functions are not thread-safe anyway.

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

101 lines
2.3 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_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;
}
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);
}