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