| // SPDX-License-Identifier: GPL-2.0 | 
 | /* | 
 |  *  linux/lib/kasprintf.c | 
 |  * | 
 |  *  Copyright (C) 1991, 1992  Linus Torvalds | 
 |  */ | 
 |  | 
 | #include <stdarg.h> | 
 | #include <linux/export.h> | 
 | #include <linux/slab.h> | 
 | #include <linux/types.h> | 
 | #include <linux/string.h> | 
 |  | 
 | /* Simplified asprintf. */ | 
 | char *kvasprintf(gfp_t gfp, const char *fmt, va_list ap) | 
 | { | 
 | 	unsigned int first, second; | 
 | 	char *p; | 
 | 	va_list aq; | 
 |  | 
 | 	va_copy(aq, ap); | 
 | 	first = vsnprintf(NULL, 0, fmt, aq); | 
 | 	va_end(aq); | 
 |  | 
 | 	p = kmalloc_track_caller(first+1, gfp); | 
 | 	if (!p) | 
 | 		return NULL; | 
 |  | 
 | 	second = vsnprintf(p, first+1, fmt, ap); | 
 | 	WARN(first != second, "different return values (%u and %u) from vsnprintf(\"%s\", ...)", | 
 | 	     first, second, fmt); | 
 |  | 
 | 	return p; | 
 | } | 
 | EXPORT_SYMBOL(kvasprintf); | 
 |  | 
 | /* | 
 |  * If fmt contains no % (or is exactly %s), use kstrdup_const. If fmt | 
 |  * (or the sole vararg) points to rodata, we will then save a memory | 
 |  * allocation and string copy. In any case, the return value should be | 
 |  * freed using kfree_const(). | 
 |  */ | 
 | const char *kvasprintf_const(gfp_t gfp, const char *fmt, va_list ap) | 
 | { | 
 | 	if (!strchr(fmt, '%')) | 
 | 		return kstrdup_const(fmt, gfp); | 
 | 	if (!strcmp(fmt, "%s")) | 
 | 		return kstrdup_const(va_arg(ap, const char*), gfp); | 
 | 	return kvasprintf(gfp, fmt, ap); | 
 | } | 
 | EXPORT_SYMBOL(kvasprintf_const); | 
 |  | 
 | char *kasprintf(gfp_t gfp, const char *fmt, ...) | 
 | { | 
 | 	va_list ap; | 
 | 	char *p; | 
 |  | 
 | 	va_start(ap, fmt); | 
 | 	p = kvasprintf(gfp, fmt, ap); | 
 | 	va_end(ap); | 
 |  | 
 | 	return p; | 
 | } | 
 | EXPORT_SYMBOL(kasprintf); |