root/vcs-svn/line_buffer.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. buffer_init
  2. buffer_fdinit
  3. buffer_tmpfile_init
  4. buffer_deinit
  5. buffer_tmpfile_rewind
  6. buffer_tmpfile_prepare_to_read
  7. buffer_ferror
  8. buffer_read_char
  9. buffer_read_line
  10. buffer_read_binary
  11. buffer_copy_bytes
  12. buffer_skip_bytes

/*
 * 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_ferror(struct line_buffer *buf)
{
        return ferror(buf->infile);
}

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;
}

size_t buffer_read_binary(struct line_buffer *buf,
                                struct strbuf *sb, size_t size)
{
        return strbuf_fread(sb, size, buf->infile);
}

off_t buffer_copy_bytes(struct line_buffer *buf, off_t nbytes)
{
        char byte_buffer[COPY_BUFFER_LEN];
        off_t done = 0;
        while (done < nbytes && !feof(buf->infile) && !ferror(buf->infile)) {
                off_t len = nbytes - done;
                size_t in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN;
                in = fread(byte_buffer, 1, in, buf->infile);
                done += in;
                fwrite(byte_buffer, 1, in, stdout);
                if (ferror(stdout))
                        return done + buffer_skip_bytes(buf, nbytes - done);
        }
        return done;
}

off_t buffer_skip_bytes(struct line_buffer *buf, off_t nbytes)
{
        char byte_buffer[COPY_BUFFER_LEN];
        off_t done = 0;
        while (done < nbytes && !feof(buf->infile) && !ferror(buf->infile)) {
                off_t len = nbytes - done;
                size_t in = len < COPY_BUFFER_LEN ? len : COPY_BUFFER_LEN;
                done += fread(byte_buffer, 1, in, buf->infile);
        }
        return done;
}

/* [<][>][^][v][top][bottom][index][help] */