diff options
author | Kent Overstreet <kent.overstreet@gmail.com> | 2022-08-18 12:32:10 -0400 |
---|---|---|
committer | Kent Overstreet <kent.overstreet@gmail.com> | 2022-08-18 12:49:48 -0400 |
commit | dded444b20dd3f47393937315b8217535ff3c51d (patch) | |
tree | c6f6b3973b5de757b458bb9e0f4c7d81e4fbef4d /linux | |
parent | 51ffcc699369deaa0fb4333a68bbbdf523afba11 (diff) |
Update bcachefs sources to dfaf9a6ee2 lib/printbuf: Clean up headers
Diffstat (limited to 'linux')
-rw-r--r-- | linux/printbuf.c | 305 | ||||
-rw-r--r-- | linux/string_helpers.c | 131 |
2 files changed, 289 insertions, 147 deletions
diff --git a/linux/printbuf.c b/linux/printbuf.c index 3fc9ff47..5cf79d43 100644 --- a/linux/printbuf.c +++ b/linux/printbuf.c @@ -2,20 +2,13 @@ /* Copyright (C) 2022 Kent Overstreet */ #include <linux/err.h> -#include <linux/math64.h> -#include <linux/printbuf.h> -#include <linux/slab.h> - -#ifdef __KERNEL__ #include <linux/export.h> #include <linux/kernel.h> -#else -#ifndef EXPORT_SYMBOL -#define EXPORT_SYMBOL(x) -#endif -#endif +#include <linux/printbuf.h> +#include <linux/slab.h> +#include <linux/string_helpers.h> -static inline size_t printbuf_linelen(struct printbuf *buf) +static inline unsigned printbuf_linelen(struct printbuf *buf) { return buf->pos - buf->last_newline; } @@ -35,6 +28,11 @@ int printbuf_make_room(struct printbuf *out, unsigned extra) return 0; new_size = roundup_pow_of_two(out->size + extra); + + /* + * Note: output buffer must be freeable with kfree(), it's not required + * that the user use printbuf_exit(). + */ buf = krealloc(out->buf, new_size, !out->atomic ? GFP_KERNEL : GFP_NOWAIT); if (!buf) { @@ -78,25 +76,43 @@ void printbuf_exit(struct printbuf *buf) } EXPORT_SYMBOL(printbuf_exit); -void prt_newline(struct printbuf *buf) +void printbuf_tabstops_reset(struct printbuf *buf) { - unsigned i; - - printbuf_make_room(buf, 1 + buf->indent); - - __prt_char(buf, '\n'); + buf->nr_tabstops = 0; +} +EXPORT_SYMBOL(printbuf_tabstops_reset); - buf->last_newline = buf->pos; +void printbuf_tabstop_pop(struct printbuf *buf) +{ + if (buf->nr_tabstops) + --buf->nr_tabstops; +} +EXPORT_SYMBOL(printbuf_tabstop_pop); - for (i = 0; i < buf->indent; i++) - __prt_char(buf, ' '); +/* + * printbuf_tabstop_set - add a tabstop, n spaces from the previous tabstop + * + * @buf: printbuf to control + * @spaces: number of spaces from previous tabpstop + * + * In the future this function may allocate memory if setting more than + * PRINTBUF_INLINE_TABSTOPS or setting tabstops more than 255 spaces from start + * of line. + */ +int printbuf_tabstop_push(struct printbuf *buf, unsigned spaces) +{ + unsigned prev_tabstop = buf->nr_tabstops + ? buf->_tabstops[buf->nr_tabstops - 1] + : 0; - printbuf_nul_terminate(buf); + if (WARN_ON(buf->nr_tabstops >= ARRAY_SIZE(buf->_tabstops))) + return -EINVAL; - buf->last_field = buf->pos; - buf->tabstop = 0; + buf->_tabstops[buf->nr_tabstops++] = prev_tabstop + spaces; + buf->has_indent_or_tabstops = true; + return 0; } -EXPORT_SYMBOL(prt_newline); +EXPORT_SYMBOL(printbuf_tabstop_push); /** * printbuf_indent_add - add to the current indent level @@ -113,8 +129,9 @@ void printbuf_indent_add(struct printbuf *buf, unsigned spaces) spaces = 0; buf->indent += spaces; - while (spaces--) - prt_char(buf, ' '); + prt_chars(buf, ' ', spaces); + + buf->has_indent_or_tabstops = true; } EXPORT_SYMBOL(printbuf_indent_add); @@ -137,168 +154,162 @@ void printbuf_indent_sub(struct printbuf *buf, unsigned spaces) printbuf_nul_terminate(buf); } buf->indent -= spaces; + + if (!buf->indent && !buf->nr_tabstops) + buf->has_indent_or_tabstops = false; } EXPORT_SYMBOL(printbuf_indent_sub); -/** - * prt_tab - Advance printbuf to the next tabstop - * - * @buf: printbuf to control - * - * Advance output to the next tabstop by printing spaces. +void prt_newline(struct printbuf *buf) +{ + unsigned i; + + printbuf_make_room(buf, 1 + buf->indent); + + __prt_char(buf, '\n'); + + buf->last_newline = buf->pos; + + for (i = 0; i < buf->indent; i++) + __prt_char(buf, ' '); + + printbuf_nul_terminate(buf); + + buf->last_field = buf->pos; + buf->cur_tabstop = 0; +} +EXPORT_SYMBOL(prt_newline); + +/* + * Returns spaces from start of line, if set, or 0 if unset: */ -void prt_tab(struct printbuf *out) +static inline unsigned cur_tabstop(struct printbuf *buf) { - int spaces = max_t(int, 0, out->tabstops[out->tabstop] - printbuf_linelen(out)); + return buf->cur_tabstop < buf->nr_tabstops + ? buf->_tabstops[buf->cur_tabstop] + : 0; +} - BUG_ON(out->tabstop > ARRAY_SIZE(out->tabstops)); +static void __prt_tab(struct printbuf *out) +{ + int spaces = max_t(int, 0, cur_tabstop(out) - printbuf_linelen(out)); prt_chars(out, ' ', spaces); out->last_field = out->pos; - out->tabstop++; + out->cur_tabstop++; } -EXPORT_SYMBOL(prt_tab); /** - * prt_tab_rjust - Advance printbuf to the next tabstop, right justifying - * previous output + * prt_tab - Advance printbuf to the next tabstop * * @buf: printbuf to control * - * Advance output to the next tabstop by inserting spaces immediately after the - * previous tabstop, right justifying previously outputted text. + * Advance output to the next tabstop by printing spaces. */ -void prt_tab_rjust(struct printbuf *buf) +void prt_tab(struct printbuf *out) { - BUG_ON(buf->tabstop > ARRAY_SIZE(buf->tabstops)); + if (WARN_ON(!cur_tabstop(out))) + return; + + __prt_tab(out); +} +EXPORT_SYMBOL(prt_tab); - if (printbuf_linelen(buf) < buf->tabstops[buf->tabstop]) { - unsigned move = buf->pos - buf->last_field; - unsigned shift = buf->tabstops[buf->tabstop] - - printbuf_linelen(buf); +static void __prt_tab_rjust(struct printbuf *buf) +{ + unsigned move = buf->pos - buf->last_field; + int pad = (int) cur_tabstop(buf) - (int) printbuf_linelen(buf); - printbuf_make_room(buf, shift); + if (pad > 0) { + printbuf_make_room(buf, pad); - if (buf->last_field + shift < buf->size) - memmove(buf->buf + buf->last_field + shift, + if (buf->last_field + pad < buf->size) + memmove(buf->buf + buf->last_field + pad, buf->buf + buf->last_field, - min(move, buf->size - 1 - buf->last_field - shift)); + min(move, buf->size - 1 - buf->last_field - pad)); if (buf->last_field < buf->size) memset(buf->buf + buf->last_field, ' ', - min(shift, buf->size - buf->last_field)); + min((unsigned) pad, buf->size - buf->last_field)); - buf->pos += shift; + buf->pos += pad; printbuf_nul_terminate(buf); } buf->last_field = buf->pos; - buf->tabstop++; + buf->cur_tabstop++; } -EXPORT_SYMBOL(prt_tab_rjust); -enum string_size_units { - STRING_UNITS_10, /* use powers of 10^3 (standard SI) */ - STRING_UNITS_2, /* use binary powers of 2^10 */ -}; -static int string_get_size(u64 size, u64 blk_size, - const enum string_size_units units, - char *buf, int len) +/** + * prt_tab_rjust - Advance printbuf to the next tabstop, right justifying + * previous output + * + * @buf: printbuf to control + * + * Advance output to the next tabstop by inserting spaces immediately after the + * previous tabstop, right justifying previously outputted text. + */ +void prt_tab_rjust(struct printbuf *buf) { - static const char *const units_10[] = { - "B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" - }; - static const char *const units_2[] = { - "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB" - }; - static const char *const *const units_str[] = { - [STRING_UNITS_10] = units_10, - [STRING_UNITS_2] = units_2, - }; - static const unsigned int divisor[] = { - [STRING_UNITS_10] = 1000, - [STRING_UNITS_2] = 1024, - }; - static const unsigned int rounding[] = { 500, 50, 5 }; - int i = 0, j; - u32 remainder = 0, sf_cap; - char tmp[13]; - const char *unit; - - tmp[0] = '\0'; - - if (blk_size == 0) - size = 0; - if (size == 0) - goto out; - - /* This is Napier's algorithm. Reduce the original block size to - * - * coefficient * divisor[units]^i - * - * we do the reduction so both coefficients are just under 32 bits so - * that multiplying them together won't overflow 64 bits and we keep - * as much precision as possible in the numbers. - * - * Note: it's safe to throw away the remainders here because all the - * precision is in the coefficients. - */ - while (blk_size >> 32) { - do_div(blk_size, divisor[units]); - i++; - } - - while (size >> 32) { - do_div(size, divisor[units]); - i++; - } + if (WARN_ON(!cur_tabstop(buf))) + return; - /* now perform the actual multiplication keeping i as the sum of the - * two logarithms */ - size *= blk_size; - - /* and logarithmically reduce it until it's just under the divisor */ - while (size >= divisor[units]) { - remainder = do_div(size, divisor[units]); - i++; - } + __prt_tab_rjust(buf); +} +EXPORT_SYMBOL(prt_tab_rjust); - /* work out in j how many digits of precision we need from the - * remainder */ - sf_cap = size; - for (j = 0; sf_cap*10 < 1000; j++) - sf_cap *= 10; - - if (units == STRING_UNITS_2) { - /* express the remainder as a decimal. It's currently the - * numerator of a fraction whose denominator is - * divisor[units], which is 1 << 10 for STRING_UNITS_2 */ - remainder *= 1000; - remainder >>= 10; - } +/** + * prt_bytes_indented - Print an array of chars, handling embedded control characters + * + * @out: printbuf to output to + * @str: string to print + * @count: number of bytes to print + * + * The following contol characters are handled as so: + * \n: prt_newline newline that obeys current indent level + * \t: prt_tab advance to next tabstop + * \r: prt_tab_rjust advance to next tabstop, with right justification + */ +void prt_bytes_indented(struct printbuf *out, const char *str, unsigned count) +{ + const char *unprinted_start = str; + const char *end = str + count; - /* add a 5 to the digit below what will be printed to ensure - * an arithmetical round up and carry it through to size */ - remainder += rounding[j]; - if (remainder >= 1000) { - remainder -= 1000; - size += 1; + if (!out->has_indent_or_tabstops || out->suppress_indent_tabstop_handling) { + prt_bytes(out, str, count); + return; } - if (j) { - snprintf(tmp, sizeof(tmp), ".%03u", remainder); - tmp[j+1] = '\0'; + while (str != end) { + switch (*str) { + case '\n': + prt_bytes(out, unprinted_start, str - unprinted_start); + unprinted_start = str + 1; + prt_newline(out); + break; + case '\t': + if (likely(cur_tabstop(out))) { + prt_bytes(out, unprinted_start, str - unprinted_start); + unprinted_start = str + 1; + __prt_tab(out); + } + break; + case '\r': + if (likely(cur_tabstop(out))) { + prt_bytes(out, unprinted_start, str - unprinted_start); + unprinted_start = str + 1; + __prt_tab_rjust(out); + } + break; + } + + str++; } - out: - if (i >= ARRAY_SIZE(units_2)) - unit = "UNK"; - else - unit = units_str[units][i]; - - return snprintf(buf, len, "%u%s %s", (u32)size, tmp, unit); + prt_bytes(out, unprinted_start, str - unprinted_start); } +EXPORT_SYMBOL(prt_bytes_indented); /** * prt_human_readable_u64 - Print out a u64 in human readable units diff --git a/linux/string_helpers.c b/linux/string_helpers.c new file mode 100644 index 00000000..3d720bc0 --- /dev/null +++ b/linux/string_helpers.c @@ -0,0 +1,131 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * Helpers for formatting and printing strings + * + * Copyright 31 August 2008 James Bottomley + * Copyright (C) 2013, Intel Corporation + */ +#include <linux/bug.h> +#include <linux/kernel.h> +#include <linux/math64.h> +#include <linux/export.h> +#include <linux/ctype.h> +#include <linux/device.h> +#include <linux/errno.h> +#include <linux/fs.h> +#include <linux/limits.h> +#include <linux/printbuf.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/string_helpers.h> + +/** + * string_get_size - get the size in the specified units + * @size: The size to be converted in blocks + * @blk_size: Size of the block (use 1 for size in bytes) + * @units: units to use (powers of 1000 or 1024) + * @buf: buffer to format to + * @len: length of buffer + * + * This function returns a string formatted to 3 significant figures + * giving the size in the required units. @buf should have room for + * at least 9 bytes and will always be zero terminated. + * + */ +int string_get_size(u64 size, u64 blk_size, const enum string_size_units units, + char *buf, int len) +{ + static const char *const units_10[] = { + "B", "kB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB" + }; + static const char *const units_2[] = { + "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "ZiB", "YiB" + }; + static const char *const *const units_str[] = { + [STRING_UNITS_10] = units_10, + [STRING_UNITS_2] = units_2, + }; + static const unsigned int divisor[] = { + [STRING_UNITS_10] = 1000, + [STRING_UNITS_2] = 1024, + }; + static const unsigned int rounding[] = { 500, 50, 5 }; + int i = 0, j; + u32 remainder = 0, sf_cap; + char tmp[8]; + const char *unit; + + tmp[0] = '\0'; + + if (blk_size == 0) + size = 0; + if (size == 0) + goto out; + + /* This is Napier's algorithm. Reduce the original block size to + * + * coefficient * divisor[units]^i + * + * we do the reduction so both coefficients are just under 32 bits so + * that multiplying them together won't overflow 64 bits and we keep + * as much precision as possible in the numbers. + * + * Note: it's safe to throw away the remainders here because all the + * precision is in the coefficients. + */ + while (blk_size >> 32) { + do_div(blk_size, divisor[units]); + i++; + } + + while (size >> 32) { + do_div(size, divisor[units]); + i++; + } + + /* now perform the actual multiplication keeping i as the sum of the + * two logarithms */ + size *= blk_size; + + /* and logarithmically reduce it until it's just under the divisor */ + while (size >= divisor[units]) { + remainder = do_div(size, divisor[units]); + i++; + } + + /* work out in j how many digits of precision we need from the + * remainder */ + sf_cap = size; + for (j = 0; sf_cap*10 < 1000; j++) + sf_cap *= 10; + + if (units == STRING_UNITS_2) { + /* express the remainder as a decimal. It's currently the + * numerator of a fraction whose denominator is + * divisor[units], which is 1 << 10 for STRING_UNITS_2 */ + remainder *= 1000; + remainder >>= 10; + } + + /* add a 5 to the digit below what will be printed to ensure + * an arithmetical round up and carry it through to size */ + remainder += rounding[j]; + if (remainder >= 1000) { + remainder -= 1000; + size += 1; + } + + if (j) { + snprintf(tmp, sizeof(tmp), ".%03u", remainder); + tmp[j+1] = '\0'; + } + + out: + if (i >= ARRAY_SIZE(units_2)) + unit = "UNK"; + else + unit = units_str[units][i]; + + return snprintf(buf, len, "%u%s %s", (u32)size, tmp, unit); +} +EXPORT_SYMBOL(string_get_size); |