18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) Paul Mackerras 1997.
48c2ecf20Sopenharmony_ci */
58c2ecf20Sopenharmony_ci#include <stdarg.h>
68c2ecf20Sopenharmony_ci#include <stddef.h>
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_cisize_t strnlen(const char * s, size_t count)
98c2ecf20Sopenharmony_ci{
108c2ecf20Sopenharmony_ci	const char *sc;
118c2ecf20Sopenharmony_ci
128c2ecf20Sopenharmony_ci	for (sc = s; count-- && *sc != '\0'; ++sc)
138c2ecf20Sopenharmony_ci		/* nothing */;
148c2ecf20Sopenharmony_ci	return sc - s;
158c2ecf20Sopenharmony_ci}
168c2ecf20Sopenharmony_ci
178c2ecf20Sopenharmony_ci# define do_div(n, base) ({						\
188c2ecf20Sopenharmony_ci	unsigned int __base = (base);					\
198c2ecf20Sopenharmony_ci	unsigned int __rem;						\
208c2ecf20Sopenharmony_ci	__rem = ((unsigned long long)(n)) % __base;			\
218c2ecf20Sopenharmony_ci	(n) = ((unsigned long long)(n)) / __base;			\
228c2ecf20Sopenharmony_ci	__rem;								\
238c2ecf20Sopenharmony_ci})
248c2ecf20Sopenharmony_ci
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cistatic int skip_atoi(const char **s)
278c2ecf20Sopenharmony_ci{
288c2ecf20Sopenharmony_ci	int i, c;
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_ci	for (i = 0; '0' <= (c = **s) && c <= '9'; ++*s)
318c2ecf20Sopenharmony_ci		i = i*10 + c - '0';
328c2ecf20Sopenharmony_ci	return i;
338c2ecf20Sopenharmony_ci}
348c2ecf20Sopenharmony_ci
358c2ecf20Sopenharmony_ci#define ZEROPAD	1		/* pad with zero */
368c2ecf20Sopenharmony_ci#define SIGN	2		/* unsigned/signed long */
378c2ecf20Sopenharmony_ci#define PLUS	4		/* show plus */
388c2ecf20Sopenharmony_ci#define SPACE	8		/* space if plus */
398c2ecf20Sopenharmony_ci#define LEFT	16		/* left justified */
408c2ecf20Sopenharmony_ci#define SPECIAL	32		/* 0x */
418c2ecf20Sopenharmony_ci#define LARGE	64		/* use 'ABCDEF' instead of 'abcdef' */
428c2ecf20Sopenharmony_ci
438c2ecf20Sopenharmony_cistatic char * number(char * str, unsigned long long num, int base, int size, int precision, int type)
448c2ecf20Sopenharmony_ci{
458c2ecf20Sopenharmony_ci	char c,sign,tmp[66];
468c2ecf20Sopenharmony_ci	const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
478c2ecf20Sopenharmony_ci	int i;
488c2ecf20Sopenharmony_ci
498c2ecf20Sopenharmony_ci	if (type & LARGE)
508c2ecf20Sopenharmony_ci		digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
518c2ecf20Sopenharmony_ci	if (type & LEFT)
528c2ecf20Sopenharmony_ci		type &= ~ZEROPAD;
538c2ecf20Sopenharmony_ci	if (base < 2 || base > 36)
548c2ecf20Sopenharmony_ci		return 0;
558c2ecf20Sopenharmony_ci	c = (type & ZEROPAD) ? '0' : ' ';
568c2ecf20Sopenharmony_ci	sign = 0;
578c2ecf20Sopenharmony_ci	if (type & SIGN) {
588c2ecf20Sopenharmony_ci		if ((signed long long)num < 0) {
598c2ecf20Sopenharmony_ci			sign = '-';
608c2ecf20Sopenharmony_ci			num = - (signed long long)num;
618c2ecf20Sopenharmony_ci			size--;
628c2ecf20Sopenharmony_ci		} else if (type & PLUS) {
638c2ecf20Sopenharmony_ci			sign = '+';
648c2ecf20Sopenharmony_ci			size--;
658c2ecf20Sopenharmony_ci		} else if (type & SPACE) {
668c2ecf20Sopenharmony_ci			sign = ' ';
678c2ecf20Sopenharmony_ci			size--;
688c2ecf20Sopenharmony_ci		}
698c2ecf20Sopenharmony_ci	}
708c2ecf20Sopenharmony_ci	if (type & SPECIAL) {
718c2ecf20Sopenharmony_ci		if (base == 16)
728c2ecf20Sopenharmony_ci			size -= 2;
738c2ecf20Sopenharmony_ci		else if (base == 8)
748c2ecf20Sopenharmony_ci			size--;
758c2ecf20Sopenharmony_ci	}
768c2ecf20Sopenharmony_ci	i = 0;
778c2ecf20Sopenharmony_ci	if (num == 0)
788c2ecf20Sopenharmony_ci		tmp[i++]='0';
798c2ecf20Sopenharmony_ci	else while (num != 0) {
808c2ecf20Sopenharmony_ci		tmp[i++] = digits[do_div(num, base)];
818c2ecf20Sopenharmony_ci	}
828c2ecf20Sopenharmony_ci	if (i > precision)
838c2ecf20Sopenharmony_ci		precision = i;
848c2ecf20Sopenharmony_ci	size -= precision;
858c2ecf20Sopenharmony_ci	if (!(type&(ZEROPAD+LEFT)))
868c2ecf20Sopenharmony_ci		while(size-->0)
878c2ecf20Sopenharmony_ci			*str++ = ' ';
888c2ecf20Sopenharmony_ci	if (sign)
898c2ecf20Sopenharmony_ci		*str++ = sign;
908c2ecf20Sopenharmony_ci	if (type & SPECIAL) {
918c2ecf20Sopenharmony_ci		if (base==8)
928c2ecf20Sopenharmony_ci			*str++ = '0';
938c2ecf20Sopenharmony_ci		else if (base==16) {
948c2ecf20Sopenharmony_ci			*str++ = '0';
958c2ecf20Sopenharmony_ci			*str++ = digits[33];
968c2ecf20Sopenharmony_ci		}
978c2ecf20Sopenharmony_ci	}
988c2ecf20Sopenharmony_ci	if (!(type & LEFT))
998c2ecf20Sopenharmony_ci		while (size-- > 0)
1008c2ecf20Sopenharmony_ci			*str++ = c;
1018c2ecf20Sopenharmony_ci	while (i < precision--)
1028c2ecf20Sopenharmony_ci		*str++ = '0';
1038c2ecf20Sopenharmony_ci	while (i-- > 0)
1048c2ecf20Sopenharmony_ci		*str++ = tmp[i];
1058c2ecf20Sopenharmony_ci	while (size-- > 0)
1068c2ecf20Sopenharmony_ci		*str++ = ' ';
1078c2ecf20Sopenharmony_ci	return str;
1088c2ecf20Sopenharmony_ci}
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ciint vsprintf(char *buf, const char *fmt, va_list args)
1118c2ecf20Sopenharmony_ci{
1128c2ecf20Sopenharmony_ci	int len;
1138c2ecf20Sopenharmony_ci	unsigned long long num;
1148c2ecf20Sopenharmony_ci	int i, base;
1158c2ecf20Sopenharmony_ci	char * str;
1168c2ecf20Sopenharmony_ci	const char *s;
1178c2ecf20Sopenharmony_ci
1188c2ecf20Sopenharmony_ci	int flags;		/* flags to number() */
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_ci	int field_width;	/* width of output field */
1218c2ecf20Sopenharmony_ci	int precision;		/* min. # of digits for integers; max
1228c2ecf20Sopenharmony_ci				   number of chars for from string */
1238c2ecf20Sopenharmony_ci	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
1248c2ecf20Sopenharmony_ci	                        /* 'z' support added 23/7/1999 S.H.    */
1258c2ecf20Sopenharmony_ci				/* 'z' changed to 'Z' --davidm 1/25/99 */
1268c2ecf20Sopenharmony_ci
1278c2ecf20Sopenharmony_ci
1288c2ecf20Sopenharmony_ci	for (str=buf ; *fmt ; ++fmt) {
1298c2ecf20Sopenharmony_ci		if (*fmt != '%') {
1308c2ecf20Sopenharmony_ci			*str++ = *fmt;
1318c2ecf20Sopenharmony_ci			continue;
1328c2ecf20Sopenharmony_ci		}
1338c2ecf20Sopenharmony_ci
1348c2ecf20Sopenharmony_ci		/* process flags */
1358c2ecf20Sopenharmony_ci		flags = 0;
1368c2ecf20Sopenharmony_ci		repeat:
1378c2ecf20Sopenharmony_ci			++fmt;		/* this also skips first '%' */
1388c2ecf20Sopenharmony_ci			switch (*fmt) {
1398c2ecf20Sopenharmony_ci				case '-': flags |= LEFT; goto repeat;
1408c2ecf20Sopenharmony_ci				case '+': flags |= PLUS; goto repeat;
1418c2ecf20Sopenharmony_ci				case ' ': flags |= SPACE; goto repeat;
1428c2ecf20Sopenharmony_ci				case '#': flags |= SPECIAL; goto repeat;
1438c2ecf20Sopenharmony_ci				case '0': flags |= ZEROPAD; goto repeat;
1448c2ecf20Sopenharmony_ci				}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_ci		/* get field width */
1478c2ecf20Sopenharmony_ci		field_width = -1;
1488c2ecf20Sopenharmony_ci		if ('0' <= *fmt && *fmt <= '9')
1498c2ecf20Sopenharmony_ci			field_width = skip_atoi(&fmt);
1508c2ecf20Sopenharmony_ci		else if (*fmt == '*') {
1518c2ecf20Sopenharmony_ci			++fmt;
1528c2ecf20Sopenharmony_ci			/* it's the next argument */
1538c2ecf20Sopenharmony_ci			field_width = va_arg(args, int);
1548c2ecf20Sopenharmony_ci			if (field_width < 0) {
1558c2ecf20Sopenharmony_ci				field_width = -field_width;
1568c2ecf20Sopenharmony_ci				flags |= LEFT;
1578c2ecf20Sopenharmony_ci			}
1588c2ecf20Sopenharmony_ci		}
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci		/* get the precision */
1618c2ecf20Sopenharmony_ci		precision = -1;
1628c2ecf20Sopenharmony_ci		if (*fmt == '.') {
1638c2ecf20Sopenharmony_ci			++fmt;
1648c2ecf20Sopenharmony_ci			if ('0' <= *fmt && *fmt <= '9')
1658c2ecf20Sopenharmony_ci				precision = skip_atoi(&fmt);
1668c2ecf20Sopenharmony_ci			else if (*fmt == '*') {
1678c2ecf20Sopenharmony_ci				++fmt;
1688c2ecf20Sopenharmony_ci				/* it's the next argument */
1698c2ecf20Sopenharmony_ci				precision = va_arg(args, int);
1708c2ecf20Sopenharmony_ci			}
1718c2ecf20Sopenharmony_ci			if (precision < 0)
1728c2ecf20Sopenharmony_ci				precision = 0;
1738c2ecf20Sopenharmony_ci		}
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci		/* get the conversion qualifier */
1768c2ecf20Sopenharmony_ci		qualifier = -1;
1778c2ecf20Sopenharmony_ci		if (*fmt == 'l' && *(fmt + 1) == 'l') {
1788c2ecf20Sopenharmony_ci			qualifier = 'q';
1798c2ecf20Sopenharmony_ci			fmt += 2;
1808c2ecf20Sopenharmony_ci		} else if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L'
1818c2ecf20Sopenharmony_ci			|| *fmt == 'Z') {
1828c2ecf20Sopenharmony_ci			qualifier = *fmt;
1838c2ecf20Sopenharmony_ci			++fmt;
1848c2ecf20Sopenharmony_ci		}
1858c2ecf20Sopenharmony_ci
1868c2ecf20Sopenharmony_ci		/* default base */
1878c2ecf20Sopenharmony_ci		base = 10;
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci		switch (*fmt) {
1908c2ecf20Sopenharmony_ci		case 'c':
1918c2ecf20Sopenharmony_ci			if (!(flags & LEFT))
1928c2ecf20Sopenharmony_ci				while (--field_width > 0)
1938c2ecf20Sopenharmony_ci					*str++ = ' ';
1948c2ecf20Sopenharmony_ci			*str++ = (unsigned char) va_arg(args, int);
1958c2ecf20Sopenharmony_ci			while (--field_width > 0)
1968c2ecf20Sopenharmony_ci				*str++ = ' ';
1978c2ecf20Sopenharmony_ci			continue;
1988c2ecf20Sopenharmony_ci
1998c2ecf20Sopenharmony_ci		case 's':
2008c2ecf20Sopenharmony_ci			s = va_arg(args, char *);
2018c2ecf20Sopenharmony_ci			if (!s)
2028c2ecf20Sopenharmony_ci				s = "<NULL>";
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci			len = strnlen(s, precision);
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_ci			if (!(flags & LEFT))
2078c2ecf20Sopenharmony_ci				while (len < field_width--)
2088c2ecf20Sopenharmony_ci					*str++ = ' ';
2098c2ecf20Sopenharmony_ci			for (i = 0; i < len; ++i)
2108c2ecf20Sopenharmony_ci				*str++ = *s++;
2118c2ecf20Sopenharmony_ci			while (len < field_width--)
2128c2ecf20Sopenharmony_ci				*str++ = ' ';
2138c2ecf20Sopenharmony_ci			continue;
2148c2ecf20Sopenharmony_ci
2158c2ecf20Sopenharmony_ci		case 'p':
2168c2ecf20Sopenharmony_ci			if (field_width == -1) {
2178c2ecf20Sopenharmony_ci				field_width = 2*sizeof(void *);
2188c2ecf20Sopenharmony_ci				flags |= ZEROPAD;
2198c2ecf20Sopenharmony_ci			}
2208c2ecf20Sopenharmony_ci			str = number(str,
2218c2ecf20Sopenharmony_ci				(unsigned long) va_arg(args, void *), 16,
2228c2ecf20Sopenharmony_ci				field_width, precision, flags);
2238c2ecf20Sopenharmony_ci			continue;
2248c2ecf20Sopenharmony_ci
2258c2ecf20Sopenharmony_ci
2268c2ecf20Sopenharmony_ci		case 'n':
2278c2ecf20Sopenharmony_ci			if (qualifier == 'l') {
2288c2ecf20Sopenharmony_ci				long * ip = va_arg(args, long *);
2298c2ecf20Sopenharmony_ci				*ip = (str - buf);
2308c2ecf20Sopenharmony_ci			} else if (qualifier == 'Z') {
2318c2ecf20Sopenharmony_ci				size_t * ip = va_arg(args, size_t *);
2328c2ecf20Sopenharmony_ci				*ip = (str - buf);
2338c2ecf20Sopenharmony_ci			} else {
2348c2ecf20Sopenharmony_ci				int * ip = va_arg(args, int *);
2358c2ecf20Sopenharmony_ci				*ip = (str - buf);
2368c2ecf20Sopenharmony_ci			}
2378c2ecf20Sopenharmony_ci			continue;
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci		case '%':
2408c2ecf20Sopenharmony_ci			*str++ = '%';
2418c2ecf20Sopenharmony_ci			continue;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci		/* integer number formats - set up the flags and "break" */
2448c2ecf20Sopenharmony_ci		case 'o':
2458c2ecf20Sopenharmony_ci			base = 8;
2468c2ecf20Sopenharmony_ci			break;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci		case 'X':
2498c2ecf20Sopenharmony_ci			flags |= LARGE;
2508c2ecf20Sopenharmony_ci		case 'x':
2518c2ecf20Sopenharmony_ci			base = 16;
2528c2ecf20Sopenharmony_ci			break;
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_ci		case 'd':
2558c2ecf20Sopenharmony_ci		case 'i':
2568c2ecf20Sopenharmony_ci			flags |= SIGN;
2578c2ecf20Sopenharmony_ci		case 'u':
2588c2ecf20Sopenharmony_ci			break;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci		default:
2618c2ecf20Sopenharmony_ci			*str++ = '%';
2628c2ecf20Sopenharmony_ci			if (*fmt)
2638c2ecf20Sopenharmony_ci				*str++ = *fmt;
2648c2ecf20Sopenharmony_ci			else
2658c2ecf20Sopenharmony_ci				--fmt;
2668c2ecf20Sopenharmony_ci			continue;
2678c2ecf20Sopenharmony_ci		}
2688c2ecf20Sopenharmony_ci		if (qualifier == 'l') {
2698c2ecf20Sopenharmony_ci			num = va_arg(args, unsigned long);
2708c2ecf20Sopenharmony_ci			if (flags & SIGN)
2718c2ecf20Sopenharmony_ci				num = (signed long) num;
2728c2ecf20Sopenharmony_ci		} else if (qualifier == 'q') {
2738c2ecf20Sopenharmony_ci			num = va_arg(args, unsigned long long);
2748c2ecf20Sopenharmony_ci			if (flags & SIGN)
2758c2ecf20Sopenharmony_ci				num = (signed long long) num;
2768c2ecf20Sopenharmony_ci		} else if (qualifier == 'Z') {
2778c2ecf20Sopenharmony_ci			num = va_arg(args, size_t);
2788c2ecf20Sopenharmony_ci		} else if (qualifier == 'h') {
2798c2ecf20Sopenharmony_ci			num = (unsigned short) va_arg(args, int);
2808c2ecf20Sopenharmony_ci			if (flags & SIGN)
2818c2ecf20Sopenharmony_ci				num = (signed short) num;
2828c2ecf20Sopenharmony_ci		} else {
2838c2ecf20Sopenharmony_ci			num = va_arg(args, unsigned int);
2848c2ecf20Sopenharmony_ci			if (flags & SIGN)
2858c2ecf20Sopenharmony_ci				num = (signed int) num;
2868c2ecf20Sopenharmony_ci		}
2878c2ecf20Sopenharmony_ci		str = number(str, num, base, field_width, precision, flags);
2888c2ecf20Sopenharmony_ci	}
2898c2ecf20Sopenharmony_ci	*str = '\0';
2908c2ecf20Sopenharmony_ci	return str-buf;
2918c2ecf20Sopenharmony_ci}
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ciint sprintf(char * buf, const char *fmt, ...)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	va_list args;
2968c2ecf20Sopenharmony_ci	int i;
2978c2ecf20Sopenharmony_ci
2988c2ecf20Sopenharmony_ci	va_start(args, fmt);
2998c2ecf20Sopenharmony_ci	i=vsprintf(buf,fmt,args);
3008c2ecf20Sopenharmony_ci	va_end(args);
3018c2ecf20Sopenharmony_ci	return i;
3028c2ecf20Sopenharmony_ci}
303