xref: /openbmc/linux/arch/powerpc/boot/stdio.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
1*2874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
266a45dd3SPaul Mackerras /*
366a45dd3SPaul Mackerras  * Copyright (C) Paul Mackerras 1997.
466a45dd3SPaul Mackerras  */
566a45dd3SPaul Mackerras #include <stdarg.h>
666a45dd3SPaul Mackerras #include <stddef.h>
766a45dd3SPaul Mackerras #include "string.h"
866a45dd3SPaul Mackerras #include "stdio.h"
9b2c5f619SMark A. Greer #include "ops.h"
1066a45dd3SPaul Mackerras 
strnlen(const char * s,size_t count)1166a45dd3SPaul Mackerras size_t strnlen(const char * s, size_t count)
1266a45dd3SPaul Mackerras {
1366a45dd3SPaul Mackerras 	const char *sc;
1466a45dd3SPaul Mackerras 
1566a45dd3SPaul Mackerras 	for (sc = s; count-- && *sc != '\0'; ++sc)
1666a45dd3SPaul Mackerras 		/* nothing */;
1766a45dd3SPaul Mackerras 	return sc - s;
1866a45dd3SPaul Mackerras }
1966a45dd3SPaul Mackerras 
strrchr(const char * s,int c)20a54b81eaSRob Herring char *strrchr(const char *s, int c)
21a54b81eaSRob Herring {
22a54b81eaSRob Herring 	const char *last = NULL;
23a54b81eaSRob Herring 	do {
24a54b81eaSRob Herring 		if (*s == (char)c)
25a54b81eaSRob Herring 			last = s;
26a54b81eaSRob Herring 	} while (*s++);
27a54b81eaSRob Herring 	return (char *)last;
28a54b81eaSRob Herring }
29a54b81eaSRob Herring 
30f4bce2f7SCédric Le Goater #ifdef __powerpc64__
31f4bce2f7SCédric Le Goater 
32f4bce2f7SCédric Le Goater # define do_div(n, base) ({						\
33f4bce2f7SCédric Le Goater 	unsigned int __base = (base);					\
34f4bce2f7SCédric Le Goater 	unsigned int __rem;						\
35f4bce2f7SCédric Le Goater 	__rem = ((unsigned long long)(n)) % __base;			\
36f4bce2f7SCédric Le Goater 	(n) = ((unsigned long long)(n)) / __base;			\
37f4bce2f7SCédric Le Goater 	__rem;								\
38f4bce2f7SCédric Le Goater })
39f4bce2f7SCédric Le Goater 
40f4bce2f7SCédric Le Goater #else
41f4bce2f7SCédric Le Goater 
4266a45dd3SPaul Mackerras extern unsigned int __div64_32(unsigned long long *dividend,
4366a45dd3SPaul Mackerras 			       unsigned int divisor);
4466a45dd3SPaul Mackerras 
4566a45dd3SPaul Mackerras /* The unnecessary pointer compare is there
4666a45dd3SPaul Mackerras  * to check for type safety (n must be 64bit)
4766a45dd3SPaul Mackerras  */
4866a45dd3SPaul Mackerras # define do_div(n,base) ({						\
4966a45dd3SPaul Mackerras 	unsigned int __base = (base);					\
5066a45dd3SPaul Mackerras 	unsigned int __rem;						\
5166a45dd3SPaul Mackerras 	(void)(((typeof((n)) *)0) == ((unsigned long long *)0));	\
5266a45dd3SPaul Mackerras 	if (((n) >> 32) == 0) {						\
5366a45dd3SPaul Mackerras 		__rem = (unsigned int)(n) % __base;			\
5466a45dd3SPaul Mackerras 		(n) = (unsigned int)(n) / __base;			\
5566a45dd3SPaul Mackerras 	} else								\
5666a45dd3SPaul Mackerras 		__rem = __div64_32(&(n), __base);			\
5766a45dd3SPaul Mackerras 	__rem;								\
5866a45dd3SPaul Mackerras  })
5966a45dd3SPaul Mackerras 
60f4bce2f7SCédric Le Goater #endif /* __powerpc64__ */
61f4bce2f7SCédric Le Goater 
skip_atoi(const char ** s)6266a45dd3SPaul Mackerras static int skip_atoi(const char **s)
6366a45dd3SPaul Mackerras {
6466a45dd3SPaul Mackerras 	int i, c;
6566a45dd3SPaul Mackerras 
6666a45dd3SPaul Mackerras 	for (i = 0; '0' <= (c = **s) && c <= '9'; ++*s)
6766a45dd3SPaul Mackerras 		i = i*10 + c - '0';
6866a45dd3SPaul Mackerras 	return i;
6966a45dd3SPaul Mackerras }
7066a45dd3SPaul Mackerras 
7166a45dd3SPaul Mackerras #define ZEROPAD	1		/* pad with zero */
7266a45dd3SPaul Mackerras #define SIGN	2		/* unsigned/signed long */
7366a45dd3SPaul Mackerras #define PLUS	4		/* show plus */
7466a45dd3SPaul Mackerras #define SPACE	8		/* space if plus */
7566a45dd3SPaul Mackerras #define LEFT	16		/* left justified */
7666a45dd3SPaul Mackerras #define SPECIAL	32		/* 0x */
7766a45dd3SPaul Mackerras #define LARGE	64		/* use 'ABCDEF' instead of 'abcdef' */
7866a45dd3SPaul Mackerras 
number(char * str,unsigned long long num,int base,int size,int precision,int type)7966a45dd3SPaul Mackerras static char * number(char * str, unsigned long long num, int base, int size, int precision, int type)
8066a45dd3SPaul Mackerras {
8166a45dd3SPaul Mackerras 	char c,sign,tmp[66];
8266a45dd3SPaul Mackerras 	const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
8366a45dd3SPaul Mackerras 	int i;
8466a45dd3SPaul Mackerras 
8566a45dd3SPaul Mackerras 	if (type & LARGE)
8666a45dd3SPaul Mackerras 		digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
8766a45dd3SPaul Mackerras 	if (type & LEFT)
8866a45dd3SPaul Mackerras 		type &= ~ZEROPAD;
8966a45dd3SPaul Mackerras 	if (base < 2 || base > 36)
9066a45dd3SPaul Mackerras 		return 0;
9166a45dd3SPaul Mackerras 	c = (type & ZEROPAD) ? '0' : ' ';
9266a45dd3SPaul Mackerras 	sign = 0;
9366a45dd3SPaul Mackerras 	if (type & SIGN) {
9466a45dd3SPaul Mackerras 		if ((signed long long)num < 0) {
9566a45dd3SPaul Mackerras 			sign = '-';
9666a45dd3SPaul Mackerras 			num = - (signed long long)num;
9766a45dd3SPaul Mackerras 			size--;
9866a45dd3SPaul Mackerras 		} else if (type & PLUS) {
9966a45dd3SPaul Mackerras 			sign = '+';
10066a45dd3SPaul Mackerras 			size--;
10166a45dd3SPaul Mackerras 		} else if (type & SPACE) {
10266a45dd3SPaul Mackerras 			sign = ' ';
10366a45dd3SPaul Mackerras 			size--;
10466a45dd3SPaul Mackerras 		}
10566a45dd3SPaul Mackerras 	}
10666a45dd3SPaul Mackerras 	if (type & SPECIAL) {
10766a45dd3SPaul Mackerras 		if (base == 16)
10866a45dd3SPaul Mackerras 			size -= 2;
10966a45dd3SPaul Mackerras 		else if (base == 8)
11066a45dd3SPaul Mackerras 			size--;
11166a45dd3SPaul Mackerras 	}
11266a45dd3SPaul Mackerras 	i = 0;
11366a45dd3SPaul Mackerras 	if (num == 0)
11466a45dd3SPaul Mackerras 		tmp[i++]='0';
11566a45dd3SPaul Mackerras 	else while (num != 0) {
11666a45dd3SPaul Mackerras 		tmp[i++] = digits[do_div(num, base)];
11766a45dd3SPaul Mackerras 	}
11866a45dd3SPaul Mackerras 	if (i > precision)
11966a45dd3SPaul Mackerras 		precision = i;
12066a45dd3SPaul Mackerras 	size -= precision;
12166a45dd3SPaul Mackerras 	if (!(type&(ZEROPAD+LEFT)))
12266a45dd3SPaul Mackerras 		while(size-->0)
12366a45dd3SPaul Mackerras 			*str++ = ' ';
12466a45dd3SPaul Mackerras 	if (sign)
12566a45dd3SPaul Mackerras 		*str++ = sign;
12666a45dd3SPaul Mackerras 	if (type & SPECIAL) {
12766a45dd3SPaul Mackerras 		if (base==8)
12866a45dd3SPaul Mackerras 			*str++ = '0';
12966a45dd3SPaul Mackerras 		else if (base==16) {
13066a45dd3SPaul Mackerras 			*str++ = '0';
13166a45dd3SPaul Mackerras 			*str++ = digits[33];
13266a45dd3SPaul Mackerras 		}
13366a45dd3SPaul Mackerras 	}
13466a45dd3SPaul Mackerras 	if (!(type & LEFT))
13566a45dd3SPaul Mackerras 		while (size-- > 0)
13666a45dd3SPaul Mackerras 			*str++ = c;
13766a45dd3SPaul Mackerras 	while (i < precision--)
13866a45dd3SPaul Mackerras 		*str++ = '0';
13966a45dd3SPaul Mackerras 	while (i-- > 0)
14066a45dd3SPaul Mackerras 		*str++ = tmp[i];
14166a45dd3SPaul Mackerras 	while (size-- > 0)
14266a45dd3SPaul Mackerras 		*str++ = ' ';
14366a45dd3SPaul Mackerras 	return str;
14466a45dd3SPaul Mackerras }
14566a45dd3SPaul Mackerras 
vsprintf(char * buf,const char * fmt,va_list args)14666a45dd3SPaul Mackerras int vsprintf(char *buf, const char *fmt, va_list args)
14766a45dd3SPaul Mackerras {
14866a45dd3SPaul Mackerras 	int len;
14966a45dd3SPaul Mackerras 	unsigned long long num;
15066a45dd3SPaul Mackerras 	int i, base;
15166a45dd3SPaul Mackerras 	char * str;
15266a45dd3SPaul Mackerras 	const char *s;
15366a45dd3SPaul Mackerras 
15466a45dd3SPaul Mackerras 	int flags;		/* flags to number() */
15566a45dd3SPaul Mackerras 
15666a45dd3SPaul Mackerras 	int field_width;	/* width of output field */
15766a45dd3SPaul Mackerras 	int precision;		/* min. # of digits for integers; max
15866a45dd3SPaul Mackerras 				   number of chars for from string */
15966a45dd3SPaul Mackerras 	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
16066a45dd3SPaul Mackerras 	                        /* 'z' support added 23/7/1999 S.H.    */
16166a45dd3SPaul Mackerras 				/* 'z' changed to 'Z' --davidm 1/25/99 */
16266a45dd3SPaul Mackerras 
16366a45dd3SPaul Mackerras 
16466a45dd3SPaul Mackerras 	for (str=buf ; *fmt ; ++fmt) {
16566a45dd3SPaul Mackerras 		if (*fmt != '%') {
16666a45dd3SPaul Mackerras 			*str++ = *fmt;
16766a45dd3SPaul Mackerras 			continue;
16866a45dd3SPaul Mackerras 		}
16966a45dd3SPaul Mackerras 
17066a45dd3SPaul Mackerras 		/* process flags */
17166a45dd3SPaul Mackerras 		flags = 0;
17266a45dd3SPaul Mackerras 		repeat:
17366a45dd3SPaul Mackerras 			++fmt;		/* this also skips first '%' */
17466a45dd3SPaul Mackerras 			switch (*fmt) {
17566a45dd3SPaul Mackerras 				case '-': flags |= LEFT; goto repeat;
17666a45dd3SPaul Mackerras 				case '+': flags |= PLUS; goto repeat;
17766a45dd3SPaul Mackerras 				case ' ': flags |= SPACE; goto repeat;
17866a45dd3SPaul Mackerras 				case '#': flags |= SPECIAL; goto repeat;
17966a45dd3SPaul Mackerras 				case '0': flags |= ZEROPAD; goto repeat;
18066a45dd3SPaul Mackerras 				}
18166a45dd3SPaul Mackerras 
18266a45dd3SPaul Mackerras 		/* get field width */
18366a45dd3SPaul Mackerras 		field_width = -1;
18466a45dd3SPaul Mackerras 		if ('0' <= *fmt && *fmt <= '9')
18566a45dd3SPaul Mackerras 			field_width = skip_atoi(&fmt);
18666a45dd3SPaul Mackerras 		else if (*fmt == '*') {
18766a45dd3SPaul Mackerras 			++fmt;
18866a45dd3SPaul Mackerras 			/* it's the next argument */
18966a45dd3SPaul Mackerras 			field_width = va_arg(args, int);
19066a45dd3SPaul Mackerras 			if (field_width < 0) {
19166a45dd3SPaul Mackerras 				field_width = -field_width;
19266a45dd3SPaul Mackerras 				flags |= LEFT;
19366a45dd3SPaul Mackerras 			}
19466a45dd3SPaul Mackerras 		}
19566a45dd3SPaul Mackerras 
19666a45dd3SPaul Mackerras 		/* get the precision */
19766a45dd3SPaul Mackerras 		precision = -1;
19866a45dd3SPaul Mackerras 		if (*fmt == '.') {
19966a45dd3SPaul Mackerras 			++fmt;
20066a45dd3SPaul Mackerras 			if ('0' <= *fmt && *fmt <= '9')
20166a45dd3SPaul Mackerras 				precision = skip_atoi(&fmt);
20266a45dd3SPaul Mackerras 			else if (*fmt == '*') {
20366a45dd3SPaul Mackerras 				++fmt;
20466a45dd3SPaul Mackerras 				/* it's the next argument */
20566a45dd3SPaul Mackerras 				precision = va_arg(args, int);
20666a45dd3SPaul Mackerras 			}
20766a45dd3SPaul Mackerras 			if (precision < 0)
20866a45dd3SPaul Mackerras 				precision = 0;
20966a45dd3SPaul Mackerras 		}
21066a45dd3SPaul Mackerras 
21166a45dd3SPaul Mackerras 		/* get the conversion qualifier */
21266a45dd3SPaul Mackerras 		qualifier = -1;
2130aa97d6eSGeoff Levand 		if (*fmt == 'l' && *(fmt + 1) == 'l') {
2140aa97d6eSGeoff Levand 			qualifier = 'q';
2150aa97d6eSGeoff Levand 			fmt += 2;
2160aa97d6eSGeoff Levand 		} else if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L'
2170aa97d6eSGeoff Levand 			|| *fmt == 'Z') {
21866a45dd3SPaul Mackerras 			qualifier = *fmt;
21966a45dd3SPaul Mackerras 			++fmt;
22066a45dd3SPaul Mackerras 		}
22166a45dd3SPaul Mackerras 
22266a45dd3SPaul Mackerras 		/* default base */
22366a45dd3SPaul Mackerras 		base = 10;
22466a45dd3SPaul Mackerras 
22566a45dd3SPaul Mackerras 		switch (*fmt) {
22666a45dd3SPaul Mackerras 		case 'c':
22766a45dd3SPaul Mackerras 			if (!(flags & LEFT))
22866a45dd3SPaul Mackerras 				while (--field_width > 0)
22966a45dd3SPaul Mackerras 					*str++ = ' ';
23066a45dd3SPaul Mackerras 			*str++ = (unsigned char) va_arg(args, int);
23166a45dd3SPaul Mackerras 			while (--field_width > 0)
23266a45dd3SPaul Mackerras 				*str++ = ' ';
23366a45dd3SPaul Mackerras 			continue;
23466a45dd3SPaul Mackerras 
23566a45dd3SPaul Mackerras 		case 's':
23666a45dd3SPaul Mackerras 			s = va_arg(args, char *);
23766a45dd3SPaul Mackerras 			if (!s)
23866a45dd3SPaul Mackerras 				s = "<NULL>";
23966a45dd3SPaul Mackerras 
24066a45dd3SPaul Mackerras 			len = strnlen(s, precision);
24166a45dd3SPaul Mackerras 
24266a45dd3SPaul Mackerras 			if (!(flags & LEFT))
24366a45dd3SPaul Mackerras 				while (len < field_width--)
24466a45dd3SPaul Mackerras 					*str++ = ' ';
24566a45dd3SPaul Mackerras 			for (i = 0; i < len; ++i)
24666a45dd3SPaul Mackerras 				*str++ = *s++;
24766a45dd3SPaul Mackerras 			while (len < field_width--)
24866a45dd3SPaul Mackerras 				*str++ = ' ';
24966a45dd3SPaul Mackerras 			continue;
25066a45dd3SPaul Mackerras 
25166a45dd3SPaul Mackerras 		case 'p':
25266a45dd3SPaul Mackerras 			if (field_width == -1) {
25366a45dd3SPaul Mackerras 				field_width = 2*sizeof(void *);
25466a45dd3SPaul Mackerras 				flags |= ZEROPAD;
25566a45dd3SPaul Mackerras 			}
25666a45dd3SPaul Mackerras 			str = number(str,
25766a45dd3SPaul Mackerras 				(unsigned long) va_arg(args, void *), 16,
25866a45dd3SPaul Mackerras 				field_width, precision, flags);
25966a45dd3SPaul Mackerras 			continue;
26066a45dd3SPaul Mackerras 
26166a45dd3SPaul Mackerras 
26266a45dd3SPaul Mackerras 		case 'n':
26366a45dd3SPaul Mackerras 			if (qualifier == 'l') {
26466a45dd3SPaul Mackerras 				long * ip = va_arg(args, long *);
26566a45dd3SPaul Mackerras 				*ip = (str - buf);
26666a45dd3SPaul Mackerras 			} else if (qualifier == 'Z') {
26766a45dd3SPaul Mackerras 				size_t * ip = va_arg(args, size_t *);
26866a45dd3SPaul Mackerras 				*ip = (str - buf);
26966a45dd3SPaul Mackerras 			} else {
27066a45dd3SPaul Mackerras 				int * ip = va_arg(args, int *);
27166a45dd3SPaul Mackerras 				*ip = (str - buf);
27266a45dd3SPaul Mackerras 			}
27366a45dd3SPaul Mackerras 			continue;
27466a45dd3SPaul Mackerras 
27566a45dd3SPaul Mackerras 		case '%':
27666a45dd3SPaul Mackerras 			*str++ = '%';
27766a45dd3SPaul Mackerras 			continue;
27866a45dd3SPaul Mackerras 
27966a45dd3SPaul Mackerras 		/* integer number formats - set up the flags and "break" */
28066a45dd3SPaul Mackerras 		case 'o':
28166a45dd3SPaul Mackerras 			base = 8;
28266a45dd3SPaul Mackerras 			break;
28366a45dd3SPaul Mackerras 
28466a45dd3SPaul Mackerras 		case 'X':
28566a45dd3SPaul Mackerras 			flags |= LARGE;
28666a45dd3SPaul Mackerras 		case 'x':
28766a45dd3SPaul Mackerras 			base = 16;
28866a45dd3SPaul Mackerras 			break;
28966a45dd3SPaul Mackerras 
29066a45dd3SPaul Mackerras 		case 'd':
29166a45dd3SPaul Mackerras 		case 'i':
29266a45dd3SPaul Mackerras 			flags |= SIGN;
29366a45dd3SPaul Mackerras 		case 'u':
29466a45dd3SPaul Mackerras 			break;
29566a45dd3SPaul Mackerras 
29666a45dd3SPaul Mackerras 		default:
29766a45dd3SPaul Mackerras 			*str++ = '%';
29866a45dd3SPaul Mackerras 			if (*fmt)
29966a45dd3SPaul Mackerras 				*str++ = *fmt;
30066a45dd3SPaul Mackerras 			else
30166a45dd3SPaul Mackerras 				--fmt;
30266a45dd3SPaul Mackerras 			continue;
30366a45dd3SPaul Mackerras 		}
30466a45dd3SPaul Mackerras 		if (qualifier == 'l') {
30566a45dd3SPaul Mackerras 			num = va_arg(args, unsigned long);
30666a45dd3SPaul Mackerras 			if (flags & SIGN)
30766a45dd3SPaul Mackerras 				num = (signed long) num;
3080aa97d6eSGeoff Levand 		} else if (qualifier == 'q') {
3090aa97d6eSGeoff Levand 			num = va_arg(args, unsigned long long);
3100aa97d6eSGeoff Levand 			if (flags & SIGN)
3110aa97d6eSGeoff Levand 				num = (signed long long) num;
31266a45dd3SPaul Mackerras 		} else if (qualifier == 'Z') {
31366a45dd3SPaul Mackerras 			num = va_arg(args, size_t);
31466a45dd3SPaul Mackerras 		} else if (qualifier == 'h') {
31566a45dd3SPaul Mackerras 			num = (unsigned short) va_arg(args, int);
31666a45dd3SPaul Mackerras 			if (flags & SIGN)
31766a45dd3SPaul Mackerras 				num = (signed short) num;
31866a45dd3SPaul Mackerras 		} else {
31966a45dd3SPaul Mackerras 			num = va_arg(args, unsigned int);
32066a45dd3SPaul Mackerras 			if (flags & SIGN)
32166a45dd3SPaul Mackerras 				num = (signed int) num;
32266a45dd3SPaul Mackerras 		}
32366a45dd3SPaul Mackerras 		str = number(str, num, base, field_width, precision, flags);
32466a45dd3SPaul Mackerras 	}
32566a45dd3SPaul Mackerras 	*str = '\0';
32666a45dd3SPaul Mackerras 	return str-buf;
32766a45dd3SPaul Mackerras }
32866a45dd3SPaul Mackerras 
sprintf(char * buf,const char * fmt,...)32966a45dd3SPaul Mackerras int sprintf(char * buf, const char *fmt, ...)
33066a45dd3SPaul Mackerras {
33166a45dd3SPaul Mackerras 	va_list args;
33266a45dd3SPaul Mackerras 	int i;
33366a45dd3SPaul Mackerras 
33466a45dd3SPaul Mackerras 	va_start(args, fmt);
33566a45dd3SPaul Mackerras 	i=vsprintf(buf,fmt,args);
33666a45dd3SPaul Mackerras 	va_end(args);
33766a45dd3SPaul Mackerras 	return i;
33866a45dd3SPaul Mackerras }
33966a45dd3SPaul Mackerras 
34066a45dd3SPaul Mackerras static char sprint_buf[1024];
34166a45dd3SPaul Mackerras 
34266a45dd3SPaul Mackerras int
printf(const char * fmt,...)34366a45dd3SPaul Mackerras printf(const char *fmt, ...)
34466a45dd3SPaul Mackerras {
34566a45dd3SPaul Mackerras 	va_list args;
34666a45dd3SPaul Mackerras 	int n;
34766a45dd3SPaul Mackerras 
34866a45dd3SPaul Mackerras 	va_start(args, fmt);
34966a45dd3SPaul Mackerras 	n = vsprintf(sprint_buf, fmt, args);
35066a45dd3SPaul Mackerras 	va_end(args);
351c888554bSMark A. Greer 	if (console_ops.write)
352b2c5f619SMark A. Greer 		console_ops.write(sprint_buf, n);
35366a45dd3SPaul Mackerras 	return n;
35466a45dd3SPaul Mackerras }
355