]> git.sesse.net Git - bcachefs-tools-debian/blob - include/linux/printbuf.h
Update bcachefs sources to 3704d0779c bcachefs: Improved human readable integer parsing
[bcachefs-tools-debian] / include / linux / printbuf.h
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /* Copyright (C) 2022 Kent Overstreet */
3
4 #ifndef _LINUX_PRINTBUF_H
5 #define _LINUX_PRINTBUF_H
6
7 /*
8  * Printbufs: Simple strings for printing to, with optional heap allocation
9  *
10  * This code has provisions for use in userspace, to aid in making other code
11  * portable between kernelspace and userspace.
12  *
13  * Basic example:
14  *   struct printbuf buf = PRINTBUF;
15  *
16  *   prt_printf(&buf, "foo=");
17  *   foo_to_text(&buf, foo);
18  *   printk("%s", buf.buf);
19  *   printbuf_exit(&buf);
20  *
21  * Or
22  *   struct printbuf buf = PRINTBUF_EXTERN(char_buf, char_buf_size)
23  *
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.
27  *
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.
31  *
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.
34  *
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.
39  *
40  * Indenting, tabstops:
41  *
42  * To aid is writing multi-line pretty printers spread across multiple
43  * functions, printbufs track the current indent level.
44  *
45  * printbuf_indent_push() and printbuf_indent_pop() increase and decrease the current indent
46  * level, respectively.
47  *
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.
53  *
54  * Make sure you use prt_newline() instead of \n in the format string for indent
55  * level and tabstops to work corretly.
56  *
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.
60  */
61
62 #include <linux/kernel.h>
63 #include <linux/string.h>
64
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
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         enum printbuf_si        si_units:1;
84         bool                    human_readable_units:1;
85         u8                      tabstop;
86         u8                      tabstops[4];
87 };
88
89 int printbuf_make_room(struct printbuf *, unsigned);
90 const char *printbuf_str(const struct printbuf *);
91 void printbuf_exit(struct printbuf *);
92
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);
102
103 /* Initializer for a heap allocated printbuf: */
104 #define PRINTBUF ((struct printbuf) { .heap_allocated = true })
105
106 /* Initializer a printbuf that points to an external buffer: */
107 #define PRINTBUF_EXTERN(_buf, _size)                    \
108 ((struct printbuf) {                                    \
109         .buf    = _buf,                                 \
110         .size   = _size,                                \
111 })
112
113 /*
114  * Returns size remaining of output buffer:
115  */
116 static inline unsigned printbuf_remaining_size(struct printbuf *out)
117 {
118         return out->pos < out->size ? out->size - out->pos : 0;
119 }
120
121 /*
122  * Returns number of characters we can print to the output buffer - i.e.
123  * excluding the terminating nul:
124  */
125 static inline unsigned printbuf_remaining(struct printbuf *out)
126 {
127         return out->pos < out->size ? out->size - out->pos - 1 : 0;
128 }
129
130 static inline unsigned printbuf_written(struct printbuf *out)
131 {
132         return min(out->pos, out->size);
133 }
134
135 /*
136  * Returns true if output was truncated:
137  */
138 static inline bool printbuf_overflowed(struct printbuf *out)
139 {
140         return out->pos >= out->size;
141 }
142
143 static inline void printbuf_nul_terminate(struct printbuf *out)
144 {
145         printbuf_make_room(out, 1);
146
147         if (out->pos < out->size)
148                 out->buf[out->pos] = 0;
149         else if (out->size)
150                 out->buf[out->size - 1] = 0;
151 }
152
153 static inline void __prt_chars_reserved(struct printbuf *out, char c, unsigned n)
154 {
155         memset(out->buf + out->pos,
156                c,
157                min(n, printbuf_remaining(out)));
158         out->pos += n;
159 }
160
161 static inline void prt_chars(struct printbuf *out, char c, unsigned n)
162 {
163         printbuf_make_room(out, n);
164         __prt_chars_reserved(out, c, n);
165         printbuf_nul_terminate(out);
166 }
167
168 /* Doesn't call printbuf_make_room(), doesn't nul terminate: */
169 static inline void __prt_char_reserved(struct printbuf *out, char c)
170 {
171         if (printbuf_remaining(out))
172                 out->buf[out->pos] = c;
173         out->pos++;
174 }
175
176 /* Doesn't nul terminate: */
177 static inline void __prt_char(struct printbuf *out, char c)
178 {
179         printbuf_make_room(out, 1);
180         __prt_char_reserved(out, c);
181 }
182
183 static inline void prt_char(struct printbuf *out, char c)
184 {
185         __prt_char(out, c);
186         printbuf_nul_terminate(out);
187 }
188
189 static inline void prt_bytes(struct printbuf *out, const void *b, unsigned n)
190 {
191         printbuf_make_room(out, n);
192
193         memcpy(out->buf + out->pos,
194                b,
195                min(n, printbuf_remaining(out)));
196         out->pos += n;
197         printbuf_nul_terminate(out);
198 }
199
200 static inline void prt_str(struct printbuf *out, const char *str)
201 {
202         prt_bytes(out, str, strlen(str));
203 }
204
205 static inline void prt_hex_byte(struct printbuf *out, u8 byte)
206 {
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);
211 }
212
213 static inline void prt_hex_byte_upper(struct printbuf *out, u8 byte)
214 {
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);
219 }
220
221 /**
222  * printbuf_reset - re-use a printbuf without freeing and re-initializing it:
223  */
224 static inline void printbuf_reset(struct printbuf *buf)
225 {
226         buf->pos                = 0;
227         buf->allocation_failure = 0;
228         buf->indent             = 0;
229         buf->tabstop            = 0;
230 }
231
232 /**
233  * printbuf_atomic_inc - mark as entering an atomic section
234  */
235 static inline void printbuf_atomic_inc(struct printbuf *buf)
236 {
237         buf->atomic++;
238 }
239
240 /**
241  * printbuf_atomic_inc - mark as leaving an atomic section
242  */
243 static inline void printbuf_atomic_dec(struct printbuf *buf)
244 {
245         buf->atomic--;
246 }
247
248 #endif /* _LINUX_PRINTBUF_H */