1401ec4dbSKent Overstreet // SPDX-License-Identifier: LGPL-2.1+ 2401ec4dbSKent Overstreet /* Copyright (C) 2022 Kent Overstreet */ 3401ec4dbSKent Overstreet 4560661d4SKent Overstreet #include <linux/bitmap.h> 5401ec4dbSKent Overstreet #include <linux/err.h> 6401ec4dbSKent Overstreet #include <linux/export.h> 7401ec4dbSKent Overstreet #include <linux/kernel.h> 8401ec4dbSKent Overstreet #include <linux/slab.h> 9401ec4dbSKent Overstreet #include <linux/string_helpers.h> 10401ec4dbSKent Overstreet 11401ec4dbSKent Overstreet #include "printbuf.h" 12401ec4dbSKent Overstreet 13*2dcb605eSKent Overstreet static inline unsigned __printbuf_linelen(struct printbuf *buf, unsigned pos) 14*2dcb605eSKent Overstreet { 15*2dcb605eSKent Overstreet return pos - buf->last_newline; 16*2dcb605eSKent Overstreet } 17*2dcb605eSKent Overstreet 18401ec4dbSKent Overstreet static inline unsigned printbuf_linelen(struct printbuf *buf) 19401ec4dbSKent Overstreet { 20*2dcb605eSKent Overstreet return __printbuf_linelen(buf, buf->pos); 21*2dcb605eSKent Overstreet } 22*2dcb605eSKent Overstreet 23*2dcb605eSKent Overstreet /* 24*2dcb605eSKent Overstreet * Returns spaces from start of line, if set, or 0 if unset: 25*2dcb605eSKent Overstreet */ 26*2dcb605eSKent Overstreet static inline unsigned cur_tabstop(struct printbuf *buf) 27*2dcb605eSKent Overstreet { 28*2dcb605eSKent Overstreet return buf->cur_tabstop < buf->nr_tabstops 29*2dcb605eSKent Overstreet ? buf->_tabstops[buf->cur_tabstop] 30*2dcb605eSKent Overstreet : 0; 31401ec4dbSKent Overstreet } 32401ec4dbSKent Overstreet 33401ec4dbSKent Overstreet int bch2_printbuf_make_room(struct printbuf *out, unsigned extra) 34401ec4dbSKent Overstreet { 35401ec4dbSKent Overstreet /* Reserved space for terminating nul: */ 36401ec4dbSKent Overstreet extra += 1; 37401ec4dbSKent Overstreet 38acce32a5SKent Overstreet if (out->pos + extra <= out->size) 39401ec4dbSKent Overstreet return 0; 40401ec4dbSKent Overstreet 41acce32a5SKent Overstreet if (!out->heap_allocated) { 42acce32a5SKent Overstreet out->overflow = true; 43acce32a5SKent Overstreet return 0; 44acce32a5SKent Overstreet } 45acce32a5SKent Overstreet 46acce32a5SKent Overstreet unsigned new_size = roundup_pow_of_two(out->size + extra); 47401ec4dbSKent Overstreet 48401ec4dbSKent Overstreet /* 49401ec4dbSKent Overstreet * Note: output buffer must be freeable with kfree(), it's not required 50401ec4dbSKent Overstreet * that the user use printbuf_exit(). 51401ec4dbSKent Overstreet */ 52acce32a5SKent Overstreet char *buf = krealloc(out->buf, new_size, !out->atomic ? GFP_KERNEL : GFP_NOWAIT); 53401ec4dbSKent Overstreet 54401ec4dbSKent Overstreet if (!buf) { 55401ec4dbSKent Overstreet out->allocation_failure = true; 56acce32a5SKent Overstreet out->overflow = true; 57401ec4dbSKent Overstreet return -ENOMEM; 58401ec4dbSKent Overstreet } 59401ec4dbSKent Overstreet 60401ec4dbSKent Overstreet out->buf = buf; 61401ec4dbSKent Overstreet out->size = new_size; 62401ec4dbSKent Overstreet return 0; 63401ec4dbSKent Overstreet } 64401ec4dbSKent Overstreet 65acce32a5SKent Overstreet static void printbuf_advance_pos(struct printbuf *out, unsigned len) 66acce32a5SKent Overstreet { 67acce32a5SKent Overstreet out->pos += min(len, printbuf_remaining(out)); 68acce32a5SKent Overstreet } 69acce32a5SKent Overstreet 70*2dcb605eSKent Overstreet static void printbuf_insert_spaces(struct printbuf *out, unsigned pos, unsigned nr) 71*2dcb605eSKent Overstreet { 72*2dcb605eSKent Overstreet unsigned move = out->pos - pos; 73*2dcb605eSKent Overstreet 74*2dcb605eSKent Overstreet bch2_printbuf_make_room(out, nr); 75*2dcb605eSKent Overstreet 76*2dcb605eSKent Overstreet if (pos + nr < out->size) 77*2dcb605eSKent Overstreet memmove(out->buf + pos + nr, 78*2dcb605eSKent Overstreet out->buf + pos, 79*2dcb605eSKent Overstreet min(move, out->size - 1 - pos - nr)); 80*2dcb605eSKent Overstreet 81*2dcb605eSKent Overstreet if (pos < out->size) 82*2dcb605eSKent Overstreet memset(out->buf + pos, ' ', min(nr, out->size - pos)); 83*2dcb605eSKent Overstreet 84*2dcb605eSKent Overstreet printbuf_advance_pos(out, nr); 85*2dcb605eSKent Overstreet printbuf_nul_terminate_reserved(out); 86*2dcb605eSKent Overstreet } 87*2dcb605eSKent Overstreet 88*2dcb605eSKent Overstreet static void __printbuf_do_indent(struct printbuf *out, unsigned pos) 89*2dcb605eSKent Overstreet { 90*2dcb605eSKent Overstreet while (true) { 91*2dcb605eSKent Overstreet int pad; 92*2dcb605eSKent Overstreet unsigned len = out->pos - pos; 93*2dcb605eSKent Overstreet char *p = out->buf + pos; 94*2dcb605eSKent Overstreet char *n = memscan(p, '\n', len); 95*2dcb605eSKent Overstreet if (cur_tabstop(out)) { 96*2dcb605eSKent Overstreet n = min(n, (char *) memscan(p, '\r', len)); 97*2dcb605eSKent Overstreet n = min(n, (char *) memscan(p, '\t', len)); 98*2dcb605eSKent Overstreet } 99*2dcb605eSKent Overstreet 100*2dcb605eSKent Overstreet pos = n - out->buf; 101*2dcb605eSKent Overstreet if (pos == out->pos) 102*2dcb605eSKent Overstreet break; 103*2dcb605eSKent Overstreet 104*2dcb605eSKent Overstreet switch (*n) { 105*2dcb605eSKent Overstreet case '\n': 106*2dcb605eSKent Overstreet pos++; 107*2dcb605eSKent Overstreet out->last_newline = pos; 108*2dcb605eSKent Overstreet 109*2dcb605eSKent Overstreet printbuf_insert_spaces(out, pos, out->indent); 110*2dcb605eSKent Overstreet 111*2dcb605eSKent Overstreet pos = min(pos + out->indent, out->pos); 112*2dcb605eSKent Overstreet out->last_field = pos; 113*2dcb605eSKent Overstreet out->cur_tabstop = 0; 114*2dcb605eSKent Overstreet break; 115*2dcb605eSKent Overstreet case '\r': 116*2dcb605eSKent Overstreet memmove(n, n + 1, out->pos - pos); 117*2dcb605eSKent Overstreet --out->pos; 118*2dcb605eSKent Overstreet pad = (int) cur_tabstop(out) - (int) __printbuf_linelen(out, pos); 119*2dcb605eSKent Overstreet if (pad > 0) { 120*2dcb605eSKent Overstreet printbuf_insert_spaces(out, out->last_field, pad); 121*2dcb605eSKent Overstreet pos += pad; 122*2dcb605eSKent Overstreet } 123*2dcb605eSKent Overstreet 124*2dcb605eSKent Overstreet out->last_field = pos; 125*2dcb605eSKent Overstreet out->cur_tabstop++; 126*2dcb605eSKent Overstreet break; 127*2dcb605eSKent Overstreet case '\t': 128*2dcb605eSKent Overstreet pad = (int) cur_tabstop(out) - (int) __printbuf_linelen(out, pos) - 1; 129*2dcb605eSKent Overstreet if (pad > 0) { 130*2dcb605eSKent Overstreet *n = ' '; 131*2dcb605eSKent Overstreet printbuf_insert_spaces(out, pos, pad - 1); 132*2dcb605eSKent Overstreet pos += pad; 133*2dcb605eSKent Overstreet } else { 134*2dcb605eSKent Overstreet memmove(n, n + 1, out->pos - pos); 135*2dcb605eSKent Overstreet --out->pos; 136*2dcb605eSKent Overstreet } 137*2dcb605eSKent Overstreet 138*2dcb605eSKent Overstreet out->last_field = pos; 139*2dcb605eSKent Overstreet out->cur_tabstop++; 140*2dcb605eSKent Overstreet break; 141*2dcb605eSKent Overstreet } 142*2dcb605eSKent Overstreet } 143*2dcb605eSKent Overstreet } 144*2dcb605eSKent Overstreet 145*2dcb605eSKent Overstreet static inline void printbuf_do_indent(struct printbuf *out, unsigned pos) 146*2dcb605eSKent Overstreet { 147*2dcb605eSKent Overstreet if (out->has_indent_or_tabstops && !out->suppress_indent_tabstop_handling) 148*2dcb605eSKent Overstreet __printbuf_do_indent(out, pos); 149*2dcb605eSKent Overstreet } 150*2dcb605eSKent Overstreet 151401ec4dbSKent Overstreet void bch2_prt_vprintf(struct printbuf *out, const char *fmt, va_list args) 152401ec4dbSKent Overstreet { 153401ec4dbSKent Overstreet int len; 154401ec4dbSKent Overstreet 155401ec4dbSKent Overstreet do { 156401ec4dbSKent Overstreet va_list args2; 157401ec4dbSKent Overstreet 158401ec4dbSKent Overstreet va_copy(args2, args); 159acce32a5SKent Overstreet len = vsnprintf(out->buf + out->pos, printbuf_remaining_size(out), fmt, args2); 160816054f4SKent Overstreet va_end(args2); 161acce32a5SKent Overstreet } while (len > printbuf_remaining(out) && 162acce32a5SKent Overstreet !bch2_printbuf_make_room(out, len)); 163401ec4dbSKent Overstreet 164*2dcb605eSKent Overstreet unsigned indent_pos = out->pos; 165acce32a5SKent Overstreet printbuf_advance_pos(out, len); 166*2dcb605eSKent Overstreet printbuf_do_indent(out, indent_pos); 167401ec4dbSKent Overstreet } 168401ec4dbSKent Overstreet 169401ec4dbSKent Overstreet void bch2_prt_printf(struct printbuf *out, const char *fmt, ...) 170401ec4dbSKent Overstreet { 171401ec4dbSKent Overstreet va_list args; 172401ec4dbSKent Overstreet int len; 173401ec4dbSKent Overstreet 174401ec4dbSKent Overstreet do { 175401ec4dbSKent Overstreet va_start(args, fmt); 176acce32a5SKent Overstreet len = vsnprintf(out->buf + out->pos, printbuf_remaining_size(out), fmt, args); 177401ec4dbSKent Overstreet va_end(args); 178acce32a5SKent Overstreet } while (len > printbuf_remaining(out) && 179acce32a5SKent Overstreet !bch2_printbuf_make_room(out, len)); 180401ec4dbSKent Overstreet 181*2dcb605eSKent Overstreet unsigned indent_pos = out->pos; 182acce32a5SKent Overstreet printbuf_advance_pos(out, len); 183*2dcb605eSKent Overstreet printbuf_do_indent(out, indent_pos); 184401ec4dbSKent Overstreet } 185401ec4dbSKent Overstreet 186401ec4dbSKent Overstreet /** 18796dea3d5SKent Overstreet * bch2_printbuf_str() - returns printbuf's buf as a C string, guaranteed to be 18896dea3d5SKent Overstreet * null terminated 18996dea3d5SKent Overstreet * @buf: printbuf to terminate 19096dea3d5SKent Overstreet * Returns: Printbuf contents, as a nul terminated C string 191401ec4dbSKent Overstreet */ 192401ec4dbSKent Overstreet const char *bch2_printbuf_str(const struct printbuf *buf) 193401ec4dbSKent Overstreet { 194401ec4dbSKent Overstreet /* 195401ec4dbSKent Overstreet * If we've written to a printbuf then it's guaranteed to be a null 196401ec4dbSKent Overstreet * terminated string - but if we haven't, then we might not have 197401ec4dbSKent Overstreet * allocated a buffer at all: 198401ec4dbSKent Overstreet */ 199401ec4dbSKent Overstreet return buf->pos 200401ec4dbSKent Overstreet ? buf->buf 201401ec4dbSKent Overstreet : ""; 202401ec4dbSKent Overstreet } 203401ec4dbSKent Overstreet 204401ec4dbSKent Overstreet /** 20596dea3d5SKent Overstreet * bch2_printbuf_exit() - exit a printbuf, freeing memory it owns and poisoning it 206401ec4dbSKent Overstreet * against accidental use. 20796dea3d5SKent Overstreet * @buf: printbuf to exit 208401ec4dbSKent Overstreet */ 209401ec4dbSKent Overstreet void bch2_printbuf_exit(struct printbuf *buf) 210401ec4dbSKent Overstreet { 211401ec4dbSKent Overstreet if (buf->heap_allocated) { 212401ec4dbSKent Overstreet kfree(buf->buf); 213401ec4dbSKent Overstreet buf->buf = ERR_PTR(-EINTR); /* poison value */ 214401ec4dbSKent Overstreet } 215401ec4dbSKent Overstreet } 216401ec4dbSKent Overstreet 217401ec4dbSKent Overstreet void bch2_printbuf_tabstops_reset(struct printbuf *buf) 218401ec4dbSKent Overstreet { 219401ec4dbSKent Overstreet buf->nr_tabstops = 0; 220401ec4dbSKent Overstreet } 221401ec4dbSKent Overstreet 222401ec4dbSKent Overstreet void bch2_printbuf_tabstop_pop(struct printbuf *buf) 223401ec4dbSKent Overstreet { 224401ec4dbSKent Overstreet if (buf->nr_tabstops) 225401ec4dbSKent Overstreet --buf->nr_tabstops; 226401ec4dbSKent Overstreet } 227401ec4dbSKent Overstreet 228401ec4dbSKent Overstreet /* 22996dea3d5SKent Overstreet * bch2_printbuf_tabstop_set() - add a tabstop, n spaces from the previous tabstop 230401ec4dbSKent Overstreet * 231401ec4dbSKent Overstreet * @buf: printbuf to control 232401ec4dbSKent Overstreet * @spaces: number of spaces from previous tabpstop 233401ec4dbSKent Overstreet * 234401ec4dbSKent Overstreet * In the future this function may allocate memory if setting more than 235401ec4dbSKent Overstreet * PRINTBUF_INLINE_TABSTOPS or setting tabstops more than 255 spaces from start 236401ec4dbSKent Overstreet * of line. 237401ec4dbSKent Overstreet */ 238401ec4dbSKent Overstreet int bch2_printbuf_tabstop_push(struct printbuf *buf, unsigned spaces) 239401ec4dbSKent Overstreet { 240401ec4dbSKent Overstreet unsigned prev_tabstop = buf->nr_tabstops 241401ec4dbSKent Overstreet ? buf->_tabstops[buf->nr_tabstops - 1] 242401ec4dbSKent Overstreet : 0; 243401ec4dbSKent Overstreet 244401ec4dbSKent Overstreet if (WARN_ON(buf->nr_tabstops >= ARRAY_SIZE(buf->_tabstops))) 245401ec4dbSKent Overstreet return -EINVAL; 246401ec4dbSKent Overstreet 247401ec4dbSKent Overstreet buf->_tabstops[buf->nr_tabstops++] = prev_tabstop + spaces; 248401ec4dbSKent Overstreet buf->has_indent_or_tabstops = true; 249401ec4dbSKent Overstreet return 0; 250401ec4dbSKent Overstreet } 251401ec4dbSKent Overstreet 252401ec4dbSKent Overstreet /** 25396dea3d5SKent Overstreet * bch2_printbuf_indent_add() - add to the current indent level 254401ec4dbSKent Overstreet * 255401ec4dbSKent Overstreet * @buf: printbuf to control 256401ec4dbSKent Overstreet * @spaces: number of spaces to add to the current indent level 257401ec4dbSKent Overstreet * 258401ec4dbSKent Overstreet * Subsequent lines, and the current line if the output position is at the start 259401ec4dbSKent Overstreet * of the current line, will be indented by @spaces more spaces. 260401ec4dbSKent Overstreet */ 261401ec4dbSKent Overstreet void bch2_printbuf_indent_add(struct printbuf *buf, unsigned spaces) 262401ec4dbSKent Overstreet { 263401ec4dbSKent Overstreet if (WARN_ON_ONCE(buf->indent + spaces < buf->indent)) 264401ec4dbSKent Overstreet spaces = 0; 265401ec4dbSKent Overstreet 266401ec4dbSKent Overstreet buf->indent += spaces; 267401ec4dbSKent Overstreet prt_chars(buf, ' ', spaces); 268401ec4dbSKent Overstreet 269401ec4dbSKent Overstreet buf->has_indent_or_tabstops = true; 270401ec4dbSKent Overstreet } 271401ec4dbSKent Overstreet 272401ec4dbSKent Overstreet /** 27396dea3d5SKent Overstreet * bch2_printbuf_indent_sub() - subtract from the current indent level 274401ec4dbSKent Overstreet * 275401ec4dbSKent Overstreet * @buf: printbuf to control 276401ec4dbSKent Overstreet * @spaces: number of spaces to subtract from the current indent level 277401ec4dbSKent Overstreet * 278401ec4dbSKent Overstreet * Subsequent lines, and the current line if the output position is at the start 279401ec4dbSKent Overstreet * of the current line, will be indented by @spaces less spaces. 280401ec4dbSKent Overstreet */ 281401ec4dbSKent Overstreet void bch2_printbuf_indent_sub(struct printbuf *buf, unsigned spaces) 282401ec4dbSKent Overstreet { 283401ec4dbSKent Overstreet if (WARN_ON_ONCE(spaces > buf->indent)) 284401ec4dbSKent Overstreet spaces = buf->indent; 285401ec4dbSKent Overstreet 286401ec4dbSKent Overstreet if (buf->last_newline + buf->indent == buf->pos) { 287401ec4dbSKent Overstreet buf->pos -= spaces; 288401ec4dbSKent Overstreet printbuf_nul_terminate(buf); 289401ec4dbSKent Overstreet } 290401ec4dbSKent Overstreet buf->indent -= spaces; 291401ec4dbSKent Overstreet 292401ec4dbSKent Overstreet if (!buf->indent && !buf->nr_tabstops) 293401ec4dbSKent Overstreet buf->has_indent_or_tabstops = false; 294401ec4dbSKent Overstreet } 295401ec4dbSKent Overstreet 296401ec4dbSKent Overstreet void bch2_prt_newline(struct printbuf *buf) 297401ec4dbSKent Overstreet { 298401ec4dbSKent Overstreet bch2_printbuf_make_room(buf, 1 + buf->indent); 299401ec4dbSKent Overstreet 300acce32a5SKent Overstreet __prt_char_reserved(buf, '\n'); 301401ec4dbSKent Overstreet 302401ec4dbSKent Overstreet buf->last_newline = buf->pos; 303401ec4dbSKent Overstreet 304acce32a5SKent Overstreet __prt_chars_reserved(buf, ' ', buf->indent); 305401ec4dbSKent Overstreet 306acce32a5SKent Overstreet printbuf_nul_terminate_reserved(buf); 307401ec4dbSKent Overstreet 308401ec4dbSKent Overstreet buf->last_field = buf->pos; 309401ec4dbSKent Overstreet buf->cur_tabstop = 0; 310401ec4dbSKent Overstreet } 311401ec4dbSKent Overstreet 312401ec4dbSKent Overstreet static void __prt_tab(struct printbuf *out) 313401ec4dbSKent Overstreet { 314401ec4dbSKent Overstreet int spaces = max_t(int, 0, cur_tabstop(out) - printbuf_linelen(out)); 315401ec4dbSKent Overstreet 316401ec4dbSKent Overstreet prt_chars(out, ' ', spaces); 317401ec4dbSKent Overstreet 318401ec4dbSKent Overstreet out->last_field = out->pos; 319401ec4dbSKent Overstreet out->cur_tabstop++; 320401ec4dbSKent Overstreet } 321401ec4dbSKent Overstreet 322401ec4dbSKent Overstreet /** 32396dea3d5SKent Overstreet * bch2_prt_tab() - Advance printbuf to the next tabstop 32496dea3d5SKent Overstreet * @out: printbuf to control 325401ec4dbSKent Overstreet * 326401ec4dbSKent Overstreet * Advance output to the next tabstop by printing spaces. 327401ec4dbSKent Overstreet */ 328401ec4dbSKent Overstreet void bch2_prt_tab(struct printbuf *out) 329401ec4dbSKent Overstreet { 330401ec4dbSKent Overstreet if (WARN_ON(!cur_tabstop(out))) 331401ec4dbSKent Overstreet return; 332401ec4dbSKent Overstreet 333401ec4dbSKent Overstreet __prt_tab(out); 334401ec4dbSKent Overstreet } 335401ec4dbSKent Overstreet 336401ec4dbSKent Overstreet static void __prt_tab_rjust(struct printbuf *buf) 337401ec4dbSKent Overstreet { 338401ec4dbSKent Overstreet int pad = (int) cur_tabstop(buf) - (int) printbuf_linelen(buf); 339*2dcb605eSKent Overstreet if (pad > 0) 340*2dcb605eSKent Overstreet printbuf_insert_spaces(buf, buf->last_field, pad); 341401ec4dbSKent Overstreet 342401ec4dbSKent Overstreet buf->last_field = buf->pos; 343401ec4dbSKent Overstreet buf->cur_tabstop++; 344401ec4dbSKent Overstreet } 345401ec4dbSKent Overstreet 346401ec4dbSKent Overstreet /** 34796dea3d5SKent Overstreet * bch2_prt_tab_rjust - Advance printbuf to the next tabstop, right justifying 348401ec4dbSKent Overstreet * previous output 349401ec4dbSKent Overstreet * 350401ec4dbSKent Overstreet * @buf: printbuf to control 351401ec4dbSKent Overstreet * 352401ec4dbSKent Overstreet * Advance output to the next tabstop by inserting spaces immediately after the 353401ec4dbSKent Overstreet * previous tabstop, right justifying previously outputted text. 354401ec4dbSKent Overstreet */ 355401ec4dbSKent Overstreet void bch2_prt_tab_rjust(struct printbuf *buf) 356401ec4dbSKent Overstreet { 357401ec4dbSKent Overstreet if (WARN_ON(!cur_tabstop(buf))) 358401ec4dbSKent Overstreet return; 359401ec4dbSKent Overstreet 360401ec4dbSKent Overstreet __prt_tab_rjust(buf); 361401ec4dbSKent Overstreet } 362401ec4dbSKent Overstreet 363401ec4dbSKent Overstreet /** 36496dea3d5SKent Overstreet * bch2_prt_bytes_indented() - Print an array of chars, handling embedded control characters 365401ec4dbSKent Overstreet * 36696dea3d5SKent Overstreet * @out: output printbuf 367401ec4dbSKent Overstreet * @str: string to print 368401ec4dbSKent Overstreet * @count: number of bytes to print 369401ec4dbSKent Overstreet * 370401ec4dbSKent Overstreet * The following contol characters are handled as so: 371401ec4dbSKent Overstreet * \n: prt_newline newline that obeys current indent level 372401ec4dbSKent Overstreet * \t: prt_tab advance to next tabstop 373401ec4dbSKent Overstreet * \r: prt_tab_rjust advance to next tabstop, with right justification 374401ec4dbSKent Overstreet */ 375401ec4dbSKent Overstreet void bch2_prt_bytes_indented(struct printbuf *out, const char *str, unsigned count) 376401ec4dbSKent Overstreet { 377*2dcb605eSKent Overstreet unsigned indent_pos = out->pos; 378401ec4dbSKent Overstreet prt_bytes(out, str, count); 379*2dcb605eSKent Overstreet printbuf_do_indent(out, indent_pos); 380401ec4dbSKent Overstreet } 381401ec4dbSKent Overstreet 382401ec4dbSKent Overstreet /** 38396dea3d5SKent Overstreet * bch2_prt_human_readable_u64() - Print out a u64 in human readable units 38496dea3d5SKent Overstreet * @out: output printbuf 38596dea3d5SKent Overstreet * @v: integer to print 386401ec4dbSKent Overstreet * 38796dea3d5SKent Overstreet * Units of 2^10 (default) or 10^3 are controlled via @out->si_units 388401ec4dbSKent Overstreet */ 38996dea3d5SKent Overstreet void bch2_prt_human_readable_u64(struct printbuf *out, u64 v) 390401ec4dbSKent Overstreet { 39196dea3d5SKent Overstreet bch2_printbuf_make_room(out, 10); 392acce32a5SKent Overstreet unsigned len = string_get_size(v, 1, !out->si_units, 39396dea3d5SKent Overstreet out->buf + out->pos, 39496dea3d5SKent Overstreet printbuf_remaining_size(out)); 395acce32a5SKent Overstreet printbuf_advance_pos(out, len); 396401ec4dbSKent Overstreet } 397401ec4dbSKent Overstreet 398401ec4dbSKent Overstreet /** 39996dea3d5SKent Overstreet * bch2_prt_human_readable_s64() - Print out a s64 in human readable units 40096dea3d5SKent Overstreet * @out: output printbuf 40196dea3d5SKent Overstreet * @v: integer to print 402401ec4dbSKent Overstreet * 40396dea3d5SKent Overstreet * Units of 2^10 (default) or 10^3 are controlled via @out->si_units 404401ec4dbSKent Overstreet */ 40596dea3d5SKent Overstreet void bch2_prt_human_readable_s64(struct printbuf *out, s64 v) 406401ec4dbSKent Overstreet { 407401ec4dbSKent Overstreet if (v < 0) 40896dea3d5SKent Overstreet prt_char(out, '-'); 40996dea3d5SKent Overstreet bch2_prt_human_readable_u64(out, abs(v)); 410401ec4dbSKent Overstreet } 411401ec4dbSKent Overstreet 412401ec4dbSKent Overstreet /** 41396dea3d5SKent Overstreet * bch2_prt_units_u64() - Print out a u64 according to printbuf unit options 41496dea3d5SKent Overstreet * @out: output printbuf 41596dea3d5SKent Overstreet * @v: integer to print 416401ec4dbSKent Overstreet * 417401ec4dbSKent Overstreet * Units are either raw (default), or human reabable units (controlled via 418401ec4dbSKent Overstreet * @buf->human_readable_units) 419401ec4dbSKent Overstreet */ 420401ec4dbSKent Overstreet void bch2_prt_units_u64(struct printbuf *out, u64 v) 421401ec4dbSKent Overstreet { 422401ec4dbSKent Overstreet if (out->human_readable_units) 423401ec4dbSKent Overstreet bch2_prt_human_readable_u64(out, v); 424401ec4dbSKent Overstreet else 425401ec4dbSKent Overstreet bch2_prt_printf(out, "%llu", v); 426401ec4dbSKent Overstreet } 427401ec4dbSKent Overstreet 428401ec4dbSKent Overstreet /** 42996dea3d5SKent Overstreet * bch2_prt_units_s64() - Print out a s64 according to printbuf unit options 43096dea3d5SKent Overstreet * @out: output printbuf 43196dea3d5SKent Overstreet * @v: integer to print 432401ec4dbSKent Overstreet * 433401ec4dbSKent Overstreet * Units are either raw (default), or human reabable units (controlled via 434401ec4dbSKent Overstreet * @buf->human_readable_units) 435401ec4dbSKent Overstreet */ 436401ec4dbSKent Overstreet void bch2_prt_units_s64(struct printbuf *out, s64 v) 437401ec4dbSKent Overstreet { 438401ec4dbSKent Overstreet if (v < 0) 439401ec4dbSKent Overstreet prt_char(out, '-'); 440401ec4dbSKent Overstreet bch2_prt_units_u64(out, abs(v)); 441401ec4dbSKent Overstreet } 442401ec4dbSKent Overstreet 443401ec4dbSKent Overstreet void bch2_prt_string_option(struct printbuf *out, 444401ec4dbSKent Overstreet const char * const list[], 445401ec4dbSKent Overstreet size_t selected) 446401ec4dbSKent Overstreet { 447acce32a5SKent Overstreet for (size_t i = 0; list[i]; i++) 448401ec4dbSKent Overstreet bch2_prt_printf(out, i == selected ? "[%s] " : "%s ", list[i]); 449401ec4dbSKent Overstreet } 450401ec4dbSKent Overstreet 451401ec4dbSKent Overstreet void bch2_prt_bitflags(struct printbuf *out, 452401ec4dbSKent Overstreet const char * const list[], u64 flags) 453401ec4dbSKent Overstreet { 454401ec4dbSKent Overstreet unsigned bit, nr = 0; 455401ec4dbSKent Overstreet bool first = true; 456401ec4dbSKent Overstreet 457401ec4dbSKent Overstreet while (list[nr]) 458401ec4dbSKent Overstreet nr++; 459401ec4dbSKent Overstreet 46048f866e9SKent Overstreet while (flags && (bit = __ffs64(flags)) < nr) { 461401ec4dbSKent Overstreet if (!first) 462401ec4dbSKent Overstreet bch2_prt_printf(out, ","); 463401ec4dbSKent Overstreet first = false; 464401ec4dbSKent Overstreet bch2_prt_printf(out, "%s", list[bit]); 46548f866e9SKent Overstreet flags ^= BIT_ULL(bit); 466401ec4dbSKent Overstreet } 467401ec4dbSKent Overstreet } 468560661d4SKent Overstreet 469560661d4SKent Overstreet void bch2_prt_bitflags_vector(struct printbuf *out, 470560661d4SKent Overstreet const char * const list[], 471560661d4SKent Overstreet unsigned long *v, unsigned nr) 472560661d4SKent Overstreet { 473560661d4SKent Overstreet bool first = true; 474560661d4SKent Overstreet unsigned i; 475560661d4SKent Overstreet 476560661d4SKent Overstreet for (i = 0; i < nr; i++) 477560661d4SKent Overstreet if (!list[i]) { 478560661d4SKent Overstreet nr = i - 1; 479560661d4SKent Overstreet break; 480560661d4SKent Overstreet } 481560661d4SKent Overstreet 482560661d4SKent Overstreet for_each_set_bit(i, v, nr) { 483560661d4SKent Overstreet if (!first) 484560661d4SKent Overstreet bch2_prt_printf(out, ","); 485560661d4SKent Overstreet first = false; 486560661d4SKent Overstreet bch2_prt_printf(out, "%s", list[i]); 487560661d4SKent Overstreet } 488560661d4SKent Overstreet } 489