printbuf.h 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. /* SPDX-License-Identifier: LGPL-2.1+ */
  2. /* Copyright (C) 2022 Kent Overstreet */
  3. #ifndef _BCACHEFS_PRINTBUF_H
  4. #define _BCACHEFS_PRINTBUF_H
  5. /*
  6. * Printbufs: Simple strings for printing to, with optional heap allocation
  7. *
  8. * This code has provisions for use in userspace, to aid in making other code
  9. * portable between kernelspace and userspace.
  10. *
  11. * Basic example:
  12. * struct printbuf buf = PRINTBUF;
  13. *
  14. * prt_printf(&buf, "foo=");
  15. * foo_to_text(&buf, foo);
  16. * printk("%s", buf.buf);
  17. * printbuf_exit(&buf);
  18. *
  19. * Or
  20. * struct printbuf buf = PRINTBUF_EXTERN(char_buf, char_buf_size)
  21. *
  22. * We can now write pretty printers instead of writing code that dumps
  23. * everything to the kernel log buffer, and then those pretty-printers can be
  24. * used by other code that outputs to kernel log, sysfs, debugfs, etc.
  25. *
  26. * Memory allocation: Outputing to a printbuf may allocate memory. This
  27. * allocation is done with GFP_KERNEL, by default: use the newer
  28. * memalloc_*_(save|restore) functions as needed.
  29. *
  30. * Since no equivalent yet exists for GFP_ATOMIC/GFP_NOWAIT, memory allocations
  31. * will be done with GFP_NOWAIT if printbuf->atomic is nonzero.
  32. *
  33. * It's allowed to grab the output buffer and free it later with kfree() instead
  34. * of using printbuf_exit(), if the user just needs a heap allocated string at
  35. * the end.
  36. *
  37. * Memory allocation failures: We don't return errors directly, because on
  38. * memory allocation failure we usually don't want to bail out and unwind - we
  39. * want to print what we've got, on a best-effort basis. But code that does want
  40. * to return -ENOMEM may check printbuf.allocation_failure.
  41. *
  42. * Indenting, tabstops:
  43. *
  44. * To aid is writing multi-line pretty printers spread across multiple
  45. * functions, printbufs track the current indent level.
  46. *
  47. * printbuf_indent_push() and printbuf_indent_pop() increase and decrease the current indent
  48. * level, respectively.
  49. *
  50. * To use tabstops, set printbuf->tabstops[]; they are in units of spaces, from
  51. * start of line. Once set, prt_tab() will output spaces up to the next tabstop.
  52. * prt_tab_rjust() will also advance the current line of text up to the next
  53. * tabstop, but it does so by shifting text since the previous tabstop up to the
  54. * next tabstop - right justifying it.
  55. *
  56. * Make sure you use prt_newline() instead of \n in the format string for indent
  57. * level and tabstops to work corretly.
  58. *
  59. * Output units: printbuf->units exists to tell pretty-printers how to output
  60. * numbers: a raw value (e.g. directly from a superblock field), as bytes, or as
  61. * human readable bytes. prt_units() obeys it.
  62. */
  63. #include <linux/kernel.h>
  64. #include <linux/string.h>
  65. enum printbuf_si {
  66. PRINTBUF_UNITS_2, /* use binary powers of 2^10 */
  67. PRINTBUF_UNITS_10, /* use powers of 10^3 (standard SI) */
  68. };
  69. #define PRINTBUF_INLINE_TABSTOPS 6
  70. struct printbuf {
  71. char *buf;
  72. unsigned size;
  73. unsigned pos;
  74. unsigned last_newline;
  75. unsigned last_field;
  76. unsigned indent;
  77. /*
  78. * If nonzero, allocations will be done with GFP_ATOMIC:
  79. */
  80. u8 atomic;
  81. bool allocation_failure:1;
  82. bool heap_allocated:1;
  83. bool overflow:1;
  84. enum printbuf_si si_units:1;
  85. bool human_readable_units:1;
  86. bool has_indent_or_tabstops:1;
  87. bool suppress_indent_tabstop_handling:1;
  88. u8 nr_tabstops;
  89. /*
  90. * Do not modify directly: use printbuf_tabstop_add(),
  91. * printbuf_tabstop_get()
  92. */
  93. u8 cur_tabstop;
  94. u8 _tabstops[PRINTBUF_INLINE_TABSTOPS];
  95. };
  96. int bch2_printbuf_make_room(struct printbuf *, unsigned);
  97. __printf(2, 3) void bch2_prt_printf(struct printbuf *out, const char *fmt, ...);
  98. __printf(2, 0) void bch2_prt_vprintf(struct printbuf *out, const char *fmt, va_list);
  99. const char *bch2_printbuf_str(const struct printbuf *);
  100. void bch2_printbuf_exit(struct printbuf *);
  101. void bch2_printbuf_tabstops_reset(struct printbuf *);
  102. void bch2_printbuf_tabstop_pop(struct printbuf *);
  103. int bch2_printbuf_tabstop_push(struct printbuf *, unsigned);
  104. void bch2_printbuf_indent_add(struct printbuf *, unsigned);
  105. void bch2_printbuf_indent_sub(struct printbuf *, unsigned);
  106. void bch2_prt_newline(struct printbuf *);
  107. void bch2_printbuf_strip_trailing_newline(struct printbuf *);
  108. void bch2_prt_tab(struct printbuf *);
  109. void bch2_prt_tab_rjust(struct printbuf *);
  110. void bch2_prt_bytes_indented(struct printbuf *, const char *, unsigned);
  111. void bch2_prt_human_readable_u64(struct printbuf *, u64);
  112. void bch2_prt_human_readable_s64(struct printbuf *, s64);
  113. void bch2_prt_units_u64(struct printbuf *, u64);
  114. void bch2_prt_units_s64(struct printbuf *, s64);
  115. void bch2_prt_string_option(struct printbuf *, const char * const[], size_t);
  116. void bch2_prt_bitflags(struct printbuf *, const char * const[], u64);
  117. void bch2_prt_bitflags_vector(struct printbuf *, const char * const[],
  118. unsigned long *, unsigned);
  119. /* Initializer for a heap allocated printbuf: */
  120. #define PRINTBUF ((struct printbuf) { .heap_allocated = true })
  121. /* Initializer a printbuf that points to an external buffer: */
  122. #define PRINTBUF_EXTERN(_buf, _size) \
  123. ((struct printbuf) { \
  124. .buf = _buf, \
  125. .size = _size, \
  126. })
  127. /*
  128. * Returns size remaining of output buffer:
  129. */
  130. static inline unsigned printbuf_remaining_size(struct printbuf *out)
  131. {
  132. if (WARN_ON(out->size && out->pos >= out->size))
  133. out->pos = out->size - 1;
  134. return out->size - out->pos;
  135. }
  136. /*
  137. * Returns number of characters we can print to the output buffer - i.e.
  138. * excluding the terminating nul:
  139. */
  140. static inline unsigned printbuf_remaining(struct printbuf *out)
  141. {
  142. return out->size ? printbuf_remaining_size(out) - 1 : 0;
  143. }
  144. static inline unsigned printbuf_written(struct printbuf *out)
  145. {
  146. return out->size ? min(out->pos, out->size - 1) : 0;
  147. }
  148. static inline void printbuf_nul_terminate_reserved(struct printbuf *out)
  149. {
  150. if (WARN_ON(out->size && out->pos >= out->size))
  151. out->pos = out->size - 1;
  152. if (out->size)
  153. out->buf[out->pos] = 0;
  154. }
  155. static inline void printbuf_nul_terminate(struct printbuf *out)
  156. {
  157. bch2_printbuf_make_room(out, 1);
  158. printbuf_nul_terminate_reserved(out);
  159. }
  160. /* Doesn't call bch2_printbuf_make_room(), doesn't nul terminate: */
  161. static inline void __prt_char_reserved(struct printbuf *out, char c)
  162. {
  163. if (printbuf_remaining(out))
  164. out->buf[out->pos++] = c;
  165. }
  166. /* Doesn't nul terminate: */
  167. static inline void __prt_char(struct printbuf *out, char c)
  168. {
  169. bch2_printbuf_make_room(out, 1);
  170. __prt_char_reserved(out, c);
  171. }
  172. static inline void prt_char(struct printbuf *out, char c)
  173. {
  174. bch2_printbuf_make_room(out, 2);
  175. __prt_char_reserved(out, c);
  176. printbuf_nul_terminate_reserved(out);
  177. }
  178. static inline void __prt_chars_reserved(struct printbuf *out, char c, unsigned n)
  179. {
  180. unsigned can_print = min(n, printbuf_remaining(out));
  181. for (unsigned i = 0; i < can_print; i++)
  182. out->buf[out->pos++] = c;
  183. }
  184. static inline void prt_chars(struct printbuf *out, char c, unsigned n)
  185. {
  186. bch2_printbuf_make_room(out, n);
  187. __prt_chars_reserved(out, c, n);
  188. printbuf_nul_terminate_reserved(out);
  189. }
  190. static inline void prt_bytes(struct printbuf *out, const void *b, unsigned n)
  191. {
  192. bch2_printbuf_make_room(out, n);
  193. unsigned can_print = min(n, printbuf_remaining(out));
  194. for (unsigned i = 0; i < can_print; i++)
  195. out->buf[out->pos++] = ((char *) b)[i];
  196. printbuf_nul_terminate(out);
  197. }
  198. static inline void prt_str(struct printbuf *out, const char *str)
  199. {
  200. prt_bytes(out, str, strlen(str));
  201. }
  202. static inline void prt_str_indented(struct printbuf *out, const char *str)
  203. {
  204. bch2_prt_bytes_indented(out, str, strlen(str));
  205. }
  206. static inline void prt_hex_byte(struct printbuf *out, u8 byte)
  207. {
  208. bch2_printbuf_make_room(out, 3);
  209. __prt_char_reserved(out, hex_asc_hi(byte));
  210. __prt_char_reserved(out, hex_asc_lo(byte));
  211. printbuf_nul_terminate_reserved(out);
  212. }
  213. static inline void prt_hex_byte_upper(struct printbuf *out, u8 byte)
  214. {
  215. bch2_printbuf_make_room(out, 3);
  216. __prt_char_reserved(out, hex_asc_upper_hi(byte));
  217. __prt_char_reserved(out, hex_asc_upper_lo(byte));
  218. printbuf_nul_terminate_reserved(out);
  219. }
  220. /**
  221. * printbuf_reset - re-use a printbuf without freeing and re-initializing it:
  222. */
  223. static inline void printbuf_reset(struct printbuf *buf)
  224. {
  225. buf->pos = 0;
  226. buf->allocation_failure = 0;
  227. buf->indent = 0;
  228. buf->nr_tabstops = 0;
  229. buf->cur_tabstop = 0;
  230. }
  231. /**
  232. * printbuf_atomic_inc - mark as entering an atomic section
  233. */
  234. static inline void printbuf_atomic_inc(struct printbuf *buf)
  235. {
  236. buf->atomic++;
  237. }
  238. /**
  239. * printbuf_atomic_inc - mark as leaving an atomic section
  240. */
  241. static inline void printbuf_atomic_dec(struct printbuf *buf)
  242. {
  243. buf->atomic--;
  244. }
  245. #endif /* _BCACHEFS_PRINTBUF_H */