126 lines
		
	
	
	
		
			2.8 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			126 lines
		
	
	
	
		
			2.8 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_errno("ftell error");
 | 
						|
	if (fseek(buf->infile, 0, SEEK_SET))
 | 
						|
		return error_errno("seek error");
 | 
						|
	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;
 | 
						|
}
 |