1047 lines · 24.6 KB · C
RawDownload
// 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/hex.h>#include <linux/limits.h>#include <linux/mm.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/string_helpers.h>#include <kunit/test.h>#include <kunit/test-bug.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), whether to include space separator * @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. * * Return value: number of characters of output that would have been written * (which may be greater than len, if output was truncated). */int string_get_size(u64 size, u64 blk_size, const enum string_size_units units,		    char *buf, int len){	enum string_size_units units_base = units & STRING_UNITS_MASK;	static const char *const units_10[] = {		"", "k", "M", "G", "T", "P", "E", "Z", "Y",	};	static const char *const units_2[] = {		"", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi", "Yi",	};	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[12];	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_base]^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_base]);		i++;	} 	while (size >> 32) {		do_div(size, divisor[units_base]);		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_base]) {		remainder = do_div(size, divisor[units_base]);		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_base == STRING_UNITS_2) {		/* express the remainder as a decimal.  It's currently the		 * numerator of a fraction whose denominator is		 * divisor[units_base], 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_base][i]; 	return snprintf(buf, len, "%u%s%s%s%s", (u32)size, tmp,			(units & STRING_UNITS_NO_SPACE) ? "" : " ",			unit,			(units & STRING_UNITS_NO_BYTES) ? "" : "B");}EXPORT_SYMBOL(string_get_size); int parse_int_array(const char *buf, size_t count, int **array){	int *ints, nints; 	get_options(buf, 0, &nints);	if (!nints)		return -ENOENT; 	ints = kzalloc_objs(*ints, nints + 1);	if (!ints)		return -ENOMEM; 	get_options(buf, nints + 1, ints);	*array = ints; 	return 0;}EXPORT_SYMBOL(parse_int_array); /** * parse_int_array_user - Split string into a sequence of integers * @from:	The user space buffer to read from * @count:	The maximum number of bytes to read * @array:	Returned pointer to sequence of integers * * On success @array is allocated and initialized with a sequence of * integers extracted from the @from plus an additional element that * begins the sequence and specifies the integers count. * * Caller takes responsibility for freeing @array when it is no longer * needed. */int parse_int_array_user(const char __user *from, size_t count, int **array){	char *buf;	int ret; 	buf = memdup_user_nul(from, count);	if (IS_ERR(buf))		return PTR_ERR(buf); 	ret = parse_int_array(buf, count, array);	kfree(buf);	return ret;}EXPORT_SYMBOL(parse_int_array_user); static bool unescape_space(char **src, char **dst){	char *p = *dst, *q = *src; 	switch (*q) {	case 'n':		*p = '\n';		break;	case 'r':		*p = '\r';		break;	case 't':		*p = '\t';		break;	case 'v':		*p = '\v';		break;	case 'f':		*p = '\f';		break;	default:		return false;	}	*dst += 1;	*src += 1;	return true;} static bool unescape_octal(char **src, char **dst){	char *p = *dst, *q = *src;	u8 num; 	if (isodigit(*q) == 0)		return false; 	num = (*q++) & 7;	while (num < 32 && isodigit(*q) && (q - *src < 3)) {		num <<= 3;		num += (*q++) & 7;	}	*p = num;	*dst += 1;	*src = q;	return true;} static bool unescape_hex(char **src, char **dst){	char *p = *dst, *q = *src;	int digit;	u8 num; 	if (*q++ != 'x')		return false; 	num = digit = hex_to_bin(*q++);	if (digit < 0)		return false; 	digit = hex_to_bin(*q);	if (digit >= 0) {		q++;		num = (num << 4) | digit;	}	*p = num;	*dst += 1;	*src = q;	return true;} static bool unescape_special(char **src, char **dst){	char *p = *dst, *q = *src; 	switch (*q) {	case '\"':		*p = '\"';		break;	case '\\':		*p = '\\';		break;	case 'a':		*p = '\a';		break;	case 'e':		*p = '\e';		break;	default:		return false;	}	*dst += 1;	*src += 1;	return true;} /** * string_unescape - unquote characters in the given string * @src:	source buffer (escaped) * @dst:	destination buffer (unescaped) * @size:	size of the destination buffer (0 to unlimit) * @flags:	combination of the flags. * * Description: * The function unquotes characters in the given string. * * Because the size of the output will be the same as or less than the size of * the input, the transformation may be performed in place. * * Caller must provide valid source and destination pointers. Be aware that * destination buffer will always be NULL-terminated. Source string must be * NULL-terminated as well.  The supported flags are:: * *	UNESCAPE_SPACE: *		'\f' - form feed *		'\n' - new line *		'\r' - carriage return *		'\t' - horizontal tab *		'\v' - vertical tab *	UNESCAPE_OCTAL: *		'\NNN' - byte with octal value NNN (1 to 3 digits) *	UNESCAPE_HEX: *		'\xHH' - byte with hexadecimal value HH (1 to 2 digits) *	UNESCAPE_SPECIAL: *		'\"' - double quote *		'\\' - backslash *		'\a' - alert (BEL) *		'\e' - escape *	UNESCAPE_ANY: *		all previous together * * Return: * The amount of the characters processed to the destination buffer excluding * trailing '\0' is returned. */int string_unescape(char *src, char *dst, size_t size, unsigned int flags){	char *out = dst; 	if (!size)		size = SIZE_MAX; 	while (*src && --size) {		if (src[0] == '\\' && src[1] != '\0' && size > 1) {			src++;			size--; 			if (flags & UNESCAPE_SPACE &&					unescape_space(&src, &out))				continue; 			if (flags & UNESCAPE_OCTAL &&					unescape_octal(&src, &out))				continue; 			if (flags & UNESCAPE_HEX &&					unescape_hex(&src, &out))				continue; 			if (flags & UNESCAPE_SPECIAL &&					unescape_special(&src, &out))				continue; 			*out++ = '\\';		}		*out++ = *src++;	}	*out = '\0'; 	return out - dst;}EXPORT_SYMBOL(string_unescape); static bool escape_passthrough(unsigned char c, char **dst, char *end){	char *out = *dst; 	if (out < end)		*out = c;	*dst = out + 1;	return true;} static bool escape_space(unsigned char c, char **dst, char *end){	char *out = *dst;	unsigned char to; 	switch (c) {	case '\n':		to = 'n';		break;	case '\r':		to = 'r';		break;	case '\t':		to = 't';		break;	case '\v':		to = 'v';		break;	case '\f':		to = 'f';		break;	default:		return false;	} 	if (out < end)		*out = '\\';	++out;	if (out < end)		*out = to;	++out; 	*dst = out;	return true;} static bool escape_special(unsigned char c, char **dst, char *end){	char *out = *dst;	unsigned char to; 	switch (c) {	case '\\':		to = '\\';		break;	case '\a':		to = 'a';		break;	case '\e':		to = 'e';		break;	case '"':		to = '"';		break;	default:		return false;	} 	if (out < end)		*out = '\\';	++out;	if (out < end)		*out = to;	++out; 	*dst = out;	return true;} static bool escape_null(unsigned char c, char **dst, char *end){	char *out = *dst; 	if (c)		return false; 	if (out < end)		*out = '\\';	++out;	if (out < end)		*out = '0';	++out; 	*dst = out;	return true;} static bool escape_octal(unsigned char c, char **dst, char *end){	char *out = *dst; 	if (out < end)		*out = '\\';	++out;	if (out < end)		*out = ((c >> 6) & 0x07) + '0';	++out;	if (out < end)		*out = ((c >> 3) & 0x07) + '0';	++out;	if (out < end)		*out = ((c >> 0) & 0x07) + '0';	++out; 	*dst = out;	return true;} static bool escape_hex(unsigned char c, char **dst, char *end){	char *out = *dst; 	if (out < end)		*out = '\\';	++out;	if (out < end)		*out = 'x';	++out;	if (out < end)		*out = hex_asc_hi(c);	++out;	if (out < end)		*out = hex_asc_lo(c);	++out; 	*dst = out;	return true;} 

Lines 1–500 of 1047.