coreboot-libre-fam15h-rdimm/3rdparty/chromeec/extra/i2c_pseudo/anprintf.h

144 lines
5.0 KiB
C

// SPDX-License-Identifier: GPL-2.0
#include <stdarg.h>
#include <linux/export.h>
#include <linux/slab.h>
#include <linux/types.h>
#include <linux/string.h>
/*
* vanprintf - Format a string and place it into a newly allocated buffer.
* @out: Address of the pointer to place the buffer address into. Will only be
* written to with a successful positive return value.
* @max_size: If non-negative, the maximum buffer size that this function will
* attempt to allocate. If the formatted string including trailing null
* character would not fit, no buffer will be allocated, and an error will
* be returned. (Thus max_size of 0 will always result in an error.)
* @gfp: GFP flags for kmalloc().
* @fmt: The format string to use.
* @ap: Arguments for the format string.
*
* Return value meanings:
*
* >=0: A buffer of this size was allocated and its address written to *out.
* The caller now owns the buffer and is responsible for freeing it with
* kfree(). The final character in the buffer, not counted in this
* return value, is the trailing null. This is the same return value
* meaning as snprintf(3).
*
* <0: An error occurred. Negate the return value for the error number.
* @out will not have been written to. Errors that might come from
* snprintf(3) may come from this function as well. Additionally, the
* following errors may occur from this function:
*
* ERANGE: A buffer larger than @max_size would be needed to fit the
* formatted string including its trailing null character.
*
* ENOMEM: Allocation of the output buffer failed.
*
* ENOTRECOVERABLE: An unexpected condition occurred. This may indicate
* a bug.
*/
static ssize_t vanprintf(char **out, ssize_t max_size, gfp_t gfp,
const char *fmt, va_list ap)
{
int ret;
ssize_t buf_size;
char *buf = NULL;
va_list args1;
va_copy(args1, ap);
ret = vsnprintf(NULL, 0, fmt, ap);
if (ret < 0) {
pr_err("%s: Formatting failed with error %d.\n", __func__,
-ret);
goto fail_before_args1;
}
if (max_size >= 0 && ret > max_size) {
ret = -ERANGE;
goto fail_before_args1;
}
buf_size = ret + 1;
buf = kmalloc(buf_size, gfp);
if (buf == NULL) {
pr_err("%s: kmalloc(%zd, %u) returned NULL\n", __func__,
buf_size, gfp);
ret = -ENOMEM;
goto fail_before_args1;
}
ret = vsnprintf(buf, buf_size, fmt, args1);
va_end(args1);
if (ret < 0) {
pr_err("%s: Second formatting pass produced error %d after the first pass succeeded. This is a bug.\n",
__func__, -ret);
goto fail_after_args1;
}
if (ret + 1 != buf_size) {
pr_err("%s: Second formatting pass produced a different formatted output size than the first. This is a bug. Will return -ENOTRECOVERABLE. first_sans_null=%zd second_sans_null=%d\n",
__func__, buf_size - 1, ret);
ret = -ENOTRECOVERABLE;
goto fail_after_args1;
}
*out = buf;
return ret;
fail_before_args1:
va_end(args1);
fail_after_args1:
kfree(buf);
if (ret >= 0) {
pr_err("%s: Jumped to failure cleanup section with non-negative return value %d set. This is a bug. Will return -ENOTRECOVERABLE instead.\n",
__func__, ret);
ret = -ENOTRECOVERABLE;
}
return ret;
}
/*
* anprintf - Format a string and place it into a newly allocated buffer.
* @out: Address of the pointer to place the buffer address into. Will only be
* written to with a successful positive return value.
* @max_size: If non-negative, the maximum buffer size that this function will
* attempt to allocate. If the formatted string including trailing null
* character would not fit, no buffer will be allocated, and an error will
* be returned. (Thus max_size of 0 will always result in an error.)
* @gfp: GFP flags for kmalloc().
* @fmt: The format string to use.
* @...: Arguments for the format string.
*
* Return value meanings:
*
* >=0: A buffer of this size was allocated and its address written to *out.
* The caller now owns the buffer and is responsible for freeing it with
* kfree(). The final character in the buffer, not counted in this
* return value, is the trailing null. This is the same return value
* meaning as snprintf(3).
*
* <0: An error occurred. Negate the return value for the error number.
* @out will not have been written to. Errors that might come from
* snprintf(3) may come from this function as well. Additionally, the
* following errors may occur from this function:
*
* ERANGE: A buffer larger than @max_size would be needed to fit the
* formatted string including its trailing null character.
*
* ENOMEM: Allocation of the output buffer failed.
*
* ENOTRECOVERABLE: An unexpected condition occurred. This may indicate
* a bug.
*/
static ssize_t anprintf(char **out, ssize_t max_size, gfp_t gfp,
const char *fmt, ...)
{
ssize_t ret;
va_list args;
va_start(args, fmt);
ret = vanprintf(out, max_size, gfp, fmt, args);
va_end(args);
return ret;
}