about summary refs log tree commit diff
path: root/vcs-svn/line_buffer.c
diff options
context:
space:
mode:
authorVincent Ambo <Vincent Ambo>2020-01-11T23·36+0000
committerVincent Ambo <Vincent Ambo>2020-01-11T23·36+0000
commit1b593e1ea4d2af0f6444d9a7788d5d99abd6fde5 (patch)
treee3accb9beed5c4c1b5a05c99db71ab2841f0ed04 /vcs-svn/line_buffer.c
Squashed 'third_party/git/' content from commit cb71568594
git-subtree-dir: third_party/git
git-subtree-split: cb715685942260375e1eb8153b0768a376e4ece7
Diffstat (limited to 'vcs-svn/line_buffer.c')
-rw-r--r--vcs-svn/line_buffer.c126
1 files changed, 126 insertions, 0 deletions
diff --git a/vcs-svn/line_buffer.c b/vcs-svn/line_buffer.c
new file mode 100644
index 000000000000..e416caf8a4fc
--- /dev/null
+++ b/vcs-svn/line_buffer.c
@@ -0,0 +1,126 @@
+/*
+ * 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;
+}