^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /* SPDX-License-Identifier: GPL-2.0 */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * Lightweight buffered reading library.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright 2019 Google LLC.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) #ifndef __API_IO__
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) #define __API_IO__
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <stdlib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <unistd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) struct io {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) /* File descriptor being read/ */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) int fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) /* Size of the read buffer. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) unsigned int buf_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) /* Pointer to storage for buffering read. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) char *buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) /* End of the storage. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) char *end;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) /* Currently accessed data pointer. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) char *data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) /* Set true on when the end of file on read error. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) bool eof;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) static inline void io__init(struct io *io, int fd,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) char *buf, unsigned int buf_len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) io->fd = fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) io->buf_len = buf_len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) io->buf = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) io->end = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) io->data = buf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) io->eof = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) /* Reads one character from the "io" file with similar semantics to fgetc. */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) static inline int io__get_char(struct io *io)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) char *ptr = io->data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) if (io->eof)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) if (ptr == io->end) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) ssize_t n = read(io->fd, io->buf, io->buf_len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) if (n <= 0) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) io->eof = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) ptr = &io->buf[0];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) io->end = &io->buf[n];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) io->data = ptr + 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) return *ptr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) /* Read a hexadecimal value with no 0x prefix into the out argument hex. If the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) * first character isn't hexadecimal returns -2, io->eof returns -1, otherwise
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) * returns the character after the hexadecimal value which may be -1 for eof.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) * If the read value is larger than a u64 the high-order bits will be dropped.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) static inline int io__get_hex(struct io *io, __u64 *hex)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) bool first_read = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) *hex = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) while (true) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72) int ch = io__get_char(io);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) if (ch < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) return ch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) if (ch >= '0' && ch <= '9')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) *hex = (*hex << 4) | (ch - '0');
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) else if (ch >= 'a' && ch <= 'f')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) *hex = (*hex << 4) | (ch - 'a' + 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) else if (ch >= 'A' && ch <= 'F')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) *hex = (*hex << 4) | (ch - 'A' + 10);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) else if (first_read)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) return -2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) return ch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) first_read = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) /* Read a positive decimal value with out argument dec. If the first character
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) * isn't a decimal returns -2, io->eof returns -1, otherwise returns the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * character after the decimal value which may be -1 for eof. If the read value
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * is larger than a u64 the high-order bits will be dropped.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) static inline int io__get_dec(struct io *io, __u64 *dec)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) bool first_read = true;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) *dec = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) while (true) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) int ch = io__get_char(io);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) if (ch < 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) return ch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) if (ch >= '0' && ch <= '9')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) *dec = (*dec * 10) + ch - '0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) else if (first_read)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) return -2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) return ch;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) first_read = false;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) #endif /* __API_IO__ */