public inbox for passt-dev@passt.top
 help / color / mirror / code / Atom feed
blob 6ffb14e37629861f40aea713cb9842ec0116847a 2717 bytes (raw)

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
 
// SPDX-License-Identifier: AGPL-3.0-or-later

/* PASST - Plug A Simple Socket Transport
 *  for qemu/UNIX domain socket mode
 *
 * PASTA - Pack A Subtle Tap Abstraction
 *  for network namespace/tap device mode
 *
 * lineread.c - Allocation free line-by-line buffered file input
 *
 * Copyright Red Hat
 * Author: David Gibson <david@gibson.dropbear.id.au>
 */

#include <stddef.h>
#include <fcntl.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>

#include "lineread.h"
#include "util.h"

/**
 * lineread_init() - Prepare for line by line file reading without allocation
 * @lr:		Line reader state structure to initialize
 * @fd:		File descriptor to read lines from
 */
void lineread_init(struct lineread *lr, int fd)
{
	lr->fd = fd;
	lr->next_line = lr->count = 0;
}

/**
 * peek_line() - Find and NULL-terminate next line in buffer
 * @lr:		Line reader state structure
 * @eof:	Caller indicates end-of-file was already found by read()
 *
 * Return: length of line in bytes, -1 if no line was found
 */
static int peek_line(struct lineread *lr, bool eof)
{
	char *nl;

	/* Sanity checks (which also document invariants) */
	ASSERT(lr->count >= 0);
	ASSERT(lr->next_line >= 0);
	ASSERT(lr->next_line + lr->count >= lr->next_line);
	ASSERT(lr->next_line + lr->count <= LINEREAD_BUFFER_SIZE);

	nl = memchr(lr->buf + lr->next_line, '\n', lr->count);

	if (nl) {
		*nl = '\0';
		return nl - lr->buf - lr->next_line + 1;
	}

	if (eof) {
		lr->buf[lr->next_line + lr->count] = '\0';
		/* No trailing newline, so treat all remaining bytes
		 * as the last line
		 */
		return lr->count;
	}

	return -1;
}

/**
 * lineread_get() - Read a single line from file (no allocation)
 * @lr:		Line reader state structure
 * @line:	Place a pointer to the next line in this variable
 *
 * Return:	Length of line read on success, 0 on EOF, negative on error
 */
int lineread_get(struct lineread *lr, char **line)
{
	bool eof = false;
	int line_len;

	while ((line_len = peek_line(lr, eof)) < 0) {
		int rc;

		if ((lr->next_line + lr->count) == LINEREAD_BUFFER_SIZE) {
			/* No space at end */
			if (lr->next_line == 0) {
				/* Buffer is full, which means we've
				 * hit a line too long for us to
				 * process.  FIXME: report error
				 * better
				 */
				return -1;
			}
			memmove(lr->buf, lr->buf + lr->next_line, lr->count);
			lr->next_line = 0;
		}

		/* Read more data into the end of buffer */
		rc = read(lr->fd, lr->buf + lr->next_line + lr->count,
			  LINEREAD_BUFFER_SIZE - lr->next_line - lr->count);
		if (rc < 0)
			return rc;

		if (rc == 0)
			eof = true;
		else
			lr->count += rc;
	}

	*line = lr->buf + lr->next_line;
	lr->next_line += line_len;
	lr->count -= line_len;
	return line_len;
}

debug log:

solving 6ffb14e ...
found 6ffb14e in https://passt.top/passt

Code repositories for project(s) associated with this public inbox

	https://passt.top/passt

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for IMAP folder(s).