1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /* Copyright (C) 2022 Kent Overstreet */
4 #ifndef _LINUX_PRINTBUF_H
5 #define _LINUX_PRINTBUF_H
8 * Printbufs: Simple strings for printing to, with optional heap allocation
10 * This code has provisions for use in userspace, to aid in making other code
11 * portable between kernelspace and userspace.
14 * struct printbuf buf = PRINTBUF;
16 * prt_printf(&buf, "foo=");
17 * foo_to_text(&buf, foo);
18 * printk("%s", buf.buf);
19 * printbuf_exit(&buf);
22 * struct printbuf buf = PRINTBUF_EXTERN(char_buf, char_buf_size)
24 * We can now write pretty printers instead of writing code that dumps
25 * everything to the kernel log buffer, and then those pretty-printers can be
26 * used by other code that outputs to kernel log, sysfs, debugfs, etc.
28 * Memory allocation: Outputing to a printbuf may allocate memory. This
29 * allocation is done with GFP_KERNEL, by default: use the newer
30 * memalloc_*_(save|restore) functions as needed.
32 * Since no equivalent yet exists for GFP_ATOMIC/GFP_NOWAIT, memory allocations
33 * will be done with GFP_NOWAIT if printbuf->atomic is nonzero.
35 * Memory allocation failures: We don't return errors directly, because on
36 * memory allocation failure we usually don't want to bail out and unwind - we
37 * want to print what we've got, on a best-effort basis. But code that does want
38 * to return -ENOMEM may check printbuf.allocation_failure.
40 * Indenting, tabstops:
42 * To aid is writing multi-line pretty printers spread across multiple
43 * functions, printbufs track the current indent level.
45 * printbuf_indent_push() and printbuf_indent_pop() increase and decrease the current indent
46 * level, respectively.
48 * To use tabstops, set printbuf->tabstops[]; they are in units of spaces, from
49 * start of line. Once set, prt_tab() will output spaces up to the next tabstop.
50 * prt_tab_rjust() will also advance the current line of text up to the next
51 * tabstop, but it does so by shifting text since the previous tabstop up to the
52 * next tabstop - right justifying it.
54 * Make sure you use prt_newline() instead of \n in the format string for indent
55 * level and tabstops to work corretly.
57 * Output units: printbuf->units exists to tell pretty-printers how to output
58 * numbers: a raw value (e.g. directly from a superblock field), as bytes, or as
59 * human readable bytes. prt_units() obeys it.
62 #include <linux/kernel.h>
63 #include <linux/string.h>
66 PRINTBUF_UNITS_2, /* use binary powers of 2^10 */
67 PRINTBUF_UNITS_10, /* use powers of 10^3 (standard SI) */
74 unsigned last_newline;
78 * If nonzero, allocations will be done with GFP_ATOMIC:
81 bool allocation_failure:1;
82 bool heap_allocated:1;
83 enum printbuf_si si_units:1;
84 bool human_readable_units:1;
89 int printbuf_make_room(struct printbuf *, unsigned);
90 const char *printbuf_str(const struct printbuf *);
91 void printbuf_exit(struct printbuf *);
93 void prt_newline(struct printbuf *);
94 void printbuf_indent_add(struct printbuf *, unsigned);
95 void printbuf_indent_sub(struct printbuf *, unsigned);
96 void prt_tab(struct printbuf *);
97 void prt_tab_rjust(struct printbuf *);
98 void prt_human_readable_u64(struct printbuf *, u64);
99 void prt_human_readable_s64(struct printbuf *, s64);
100 void prt_units_u64(struct printbuf *, u64);
101 void prt_units_s64(struct printbuf *, s64);
103 /* Initializer for a heap allocated printbuf: */
104 #define PRINTBUF ((struct printbuf) { .heap_allocated = true })
106 /* Initializer a printbuf that points to an external buffer: */
107 #define PRINTBUF_EXTERN(_buf, _size) \
108 ((struct printbuf) { \
114 * Returns size remaining of output buffer:
116 static inline unsigned printbuf_remaining_size(struct printbuf *out)
118 return out->pos < out->size ? out->size - out->pos : 0;
122 * Returns number of characters we can print to the output buffer - i.e.
123 * excluding the terminating nul:
125 static inline unsigned printbuf_remaining(struct printbuf *out)
127 return out->pos < out->size ? out->size - out->pos - 1 : 0;
130 static inline unsigned printbuf_written(struct printbuf *out)
132 return min(out->pos, out->size);
136 * Returns true if output was truncated:
138 static inline bool printbuf_overflowed(struct printbuf *out)
140 return out->pos >= out->size;
143 static inline void printbuf_nul_terminate(struct printbuf *out)
145 printbuf_make_room(out, 1);
147 if (out->pos < out->size)
148 out->buf[out->pos] = 0;
150 out->buf[out->size - 1] = 0;
153 static inline void __prt_chars_reserved(struct printbuf *out, char c, unsigned n)
155 memset(out->buf + out->pos,
157 min(n, printbuf_remaining(out)));
161 static inline void prt_chars(struct printbuf *out, char c, unsigned n)
163 printbuf_make_room(out, n);
164 __prt_chars_reserved(out, c, n);
165 printbuf_nul_terminate(out);
168 /* Doesn't call printbuf_make_room(), doesn't nul terminate: */
169 static inline void __prt_char_reserved(struct printbuf *out, char c)
171 if (printbuf_remaining(out))
172 out->buf[out->pos] = c;
176 /* Doesn't nul terminate: */
177 static inline void __prt_char(struct printbuf *out, char c)
179 printbuf_make_room(out, 1);
180 __prt_char_reserved(out, c);
183 static inline void prt_char(struct printbuf *out, char c)
186 printbuf_nul_terminate(out);
189 static inline void prt_bytes(struct printbuf *out, const void *b, unsigned n)
191 printbuf_make_room(out, n);
193 memcpy(out->buf + out->pos,
195 min(n, printbuf_remaining(out)));
197 printbuf_nul_terminate(out);
200 static inline void prt_str(struct printbuf *out, const char *str)
202 prt_bytes(out, str, strlen(str));
205 static inline void prt_hex_byte(struct printbuf *out, u8 byte)
207 printbuf_make_room(out, 2);
208 __prt_char_reserved(out, hex_asc_hi(byte));
209 __prt_char_reserved(out, hex_asc_lo(byte));
210 printbuf_nul_terminate(out);
213 static inline void prt_hex_byte_upper(struct printbuf *out, u8 byte)
215 printbuf_make_room(out, 2);
216 __prt_char_reserved(out, hex_asc_upper_hi(byte));
217 __prt_char_reserved(out, hex_asc_upper_lo(byte));
218 printbuf_nul_terminate(out);
222 * printbuf_reset - re-use a printbuf without freeing and re-initializing it:
224 static inline void printbuf_reset(struct printbuf *buf)
227 buf->allocation_failure = 0;
233 * printbuf_atomic_inc - mark as entering an atomic section
235 static inline void printbuf_atomic_inc(struct printbuf *buf)
241 * printbuf_atomic_inc - mark as leaving an atomic section
243 static inline void printbuf_atomic_dec(struct printbuf *buf)
248 #endif /* _LINUX_PRINTBUF_H */