io.h 4.2 KB

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