brintos

brintos / linux-shallow public Read only

0
0
Text · 4.2 KiB · d3eb04d Raw
201 lines · c
1/* SPDX-License-Identifier: GPL-2.0 */2/*3 * Lightweight buffered reading library.4 *5 * Copyright 2019 Google LLC.6 */7#ifndef __API_IO__8#define __API_IO__9 10#include <errno.h>11#include <poll.h>12#include <stdlib.h>13#include <string.h>14#include <unistd.h>15#include <linux/types.h>16 17struct io {18	/* File descriptor being read/ */19	int fd;20	/* Size of the read buffer. */21	unsigned int buf_len;22	/* Pointer to storage for buffering read. */23	char *buf;24	/* End of the storage. */25	char *end;26	/* Currently accessed data pointer. */27	char *data;28	/* Read timeout, 0 implies no timeout. */29	int timeout_ms;30	/* Set true on when the end of file on read error. */31	bool eof;32};33 34static inline void io__init(struct io *io, int fd,35			    char *buf, unsigned int buf_len)36{37	io->fd = fd;38	io->buf_len = buf_len;39	io->buf = buf;40	io->end = buf;41	io->data = buf;42	io->timeout_ms = 0;43	io->eof = false;44}45 46/* Read from fd filling the buffer. Called when io->data == io->end. */47static inline int io__fill_buffer(struct io *io)48{49	ssize_t n;50 51	if (io->eof)52		return -1;53 54	if (io->timeout_ms != 0) {55		struct pollfd pfds[] = {56			{57				.fd = io->fd,58				.events = POLLIN,59			},60		};61 62		n = poll(pfds, 1, io->timeout_ms);63		if (n == 0)64			errno = ETIMEDOUT;65		if (n > 0 && !(pfds[0].revents & POLLIN)) {66			errno = EIO;67			n = -1;68		}69		if (n <= 0) {70			io->eof = true;71			return -1;72		}73	}74	n = read(io->fd, io->buf, io->buf_len);75 76	if (n <= 0) {77		io->eof = true;78		return -1;79	}80	io->data = &io->buf[0];81	io->end = &io->buf[n];82	return 0;83}84 85/* Reads one character from the "io" file with similar semantics to fgetc. */86static inline int io__get_char(struct io *io)87{88	if (io->data == io->end) {89		int ret = io__fill_buffer(io);90 91		if (ret)92			return ret;93	}94	return *io->data++;95}96 97/* Read a hexadecimal value with no 0x prefix into the out argument hex. If the98 * first character isn't hexadecimal returns -2, io->eof returns -1, otherwise99 * returns the character after the hexadecimal value which may be -1 for eof.100 * If the read value is larger than a u64 the high-order bits will be dropped.101 */102static inline int io__get_hex(struct io *io, __u64 *hex)103{104	bool first_read = true;105 106	*hex = 0;107	while (true) {108		int ch = io__get_char(io);109 110		if (ch < 0)111			return ch;112		if (ch >= '0' && ch <= '9')113			*hex = (*hex << 4) | (ch - '0');114		else if (ch >= 'a' && ch <= 'f')115			*hex = (*hex << 4) | (ch - 'a' + 10);116		else if (ch >= 'A' && ch <= 'F')117			*hex = (*hex << 4) | (ch - 'A' + 10);118		else if (first_read)119			return -2;120		else121			return ch;122		first_read = false;123	}124}125 126/* Read a positive decimal value with out argument dec. If the first character127 * isn't a decimal returns -2, io->eof returns -1, otherwise returns the128 * character after the decimal value which may be -1 for eof. If the read value129 * is larger than a u64 the high-order bits will be dropped.130 */131static inline int io__get_dec(struct io *io, __u64 *dec)132{133	bool first_read = true;134 135	*dec = 0;136	while (true) {137		int ch = io__get_char(io);138 139		if (ch < 0)140			return ch;141		if (ch >= '0' && ch <= '9')142			*dec = (*dec * 10) + ch - '0';143		else if (first_read)144			return -2;145		else146			return ch;147		first_read = false;148	}149}150 151/* Read up to and including the first delim. */152static inline ssize_t io__getdelim(struct io *io, char **line_out, size_t *line_len_out, int delim)153{154	char buf[128];155	int buf_pos = 0;156	char *line = NULL, *temp;157	size_t line_len = 0;158	int ch = 0;159 160	/* TODO: reuse previously allocated memory. */161	free(*line_out);162	while (ch != delim) {163		ch = io__get_char(io);164 165		if (ch < 0)166			break;167 168		if (buf_pos == sizeof(buf)) {169			temp = realloc(line, line_len + sizeof(buf));170			if (!temp)171				goto err_out;172			line = temp;173			memcpy(&line[line_len], buf, sizeof(buf));174			line_len += sizeof(buf);175			buf_pos = 0;176		}177		buf[buf_pos++] = (char)ch;178	}179	temp = realloc(line, line_len + buf_pos + 1);180	if (!temp)181		goto err_out;182	line = temp;183	memcpy(&line[line_len], buf, buf_pos);184	line[line_len + buf_pos] = '\0';185	line_len += buf_pos;186	*line_out = line;187	*line_len_out = line_len;188	return line_len;189err_out:190	free(line);191	*line_out = NULL;192	return -ENOMEM;193}194 195static inline ssize_t io__getline(struct io *io, char **line_out, size_t *line_len_out)196{197	return io__getdelim(io, line_out, line_len_out, /*delim=*/'\n');198}199 200#endif /* __API_IO__ */201