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