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