xref: /openbmc/linux/arch/powerpc/boot/stdio.c (revision 2874c5fd)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) Paul Mackerras 1997.
4  */
5 #include <stdarg.h>
6 #include <stddef.h>
7 #include "string.h"
8 #include "stdio.h"
9 #include "ops.h"
10 
strnlen(const char * s,size_t count)11 size_t strnlen(const char * s, size_t count)
12 {
13 	const char *sc;
14 
15 	for (sc = s; count-- && *sc != '\0'; ++sc)
16 		/* nothing */;
17 	return sc - s;
18 }
19 
strrchr(const char * s,int c)20 char *strrchr(const char *s, int c)
21 {
22 	const char *last = NULL;
23 	do {
24 		if (*s == (char)c)
25 			last = s;
26 	} while (*s++);
27 	return (char *)last;
28 }
29 
30 #ifdef __powerpc64__
31 
32 # define do_div(n, base) ({						\
33 	unsigned int __base = (base);					\
34 	unsigned int __rem;						\
35 	__rem = ((unsigned long long)(n)) % __base;			\
36 	(n) = ((unsigned long long)(n)) / __base;			\
37 	__rem;								\
38 })
39 
40 #else
41 
42 extern unsigned int __div64_32(unsigned long long *dividend,
43 			       unsigned int divisor);
44 
45 /* The unnecessary pointer compare is there
46  * to check for type safety (n must be 64bit)
47  */
48 # define do_div(n,base) ({						\
49 	unsigned int __base = (base);					\
50 	unsigned int __rem;						\
51 	(void)(((typeof((n)) *)0) == ((unsigned long long *)0));	\
52 	if (((n) >> 32) == 0) {						\
53 		__rem = (unsigned int)(n) % __base;			\
54 		(n) = (unsigned int)(n) / __base;			\
55 	} else								\
56 		__rem = __div64_32(&(n), __base);			\
57 	__rem;								\
58  })
59 
60 #endif /* __powerpc64__ */
61 
skip_atoi(const char ** s)62 static int skip_atoi(const char **s)
63 {
64 	int i, c;
65 
66 	for (i = 0; '0' <= (c = **s) && c <= '9'; ++*s)
67 		i = i*10 + c - '0';
68 	return i;
69 }
70 
71 #define ZEROPAD	1		/* pad with zero */
72 #define SIGN	2		/* unsigned/signed long */
73 #define PLUS	4		/* show plus */
74 #define SPACE	8		/* space if plus */
75 #define LEFT	16		/* left justified */
76 #define SPECIAL	32		/* 0x */
77 #define LARGE	64		/* use 'ABCDEF' instead of 'abcdef' */
78 
number(char * str,unsigned long long num,int base,int size,int precision,int type)79 static char * number(char * str, unsigned long long num, int base, int size, int precision, int type)
80 {
81 	char c,sign,tmp[66];
82 	const char *digits="0123456789abcdefghijklmnopqrstuvwxyz";
83 	int i;
84 
85 	if (type & LARGE)
86 		digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
87 	if (type & LEFT)
88 		type &= ~ZEROPAD;
89 	if (base < 2 || base > 36)
90 		return 0;
91 	c = (type & ZEROPAD) ? '0' : ' ';
92 	sign = 0;
93 	if (type & SIGN) {
94 		if ((signed long long)num < 0) {
95 			sign = '-';
96 			num = - (signed long long)num;
97 			size--;
98 		} else if (type & PLUS) {
99 			sign = '+';
100 			size--;
101 		} else if (type & SPACE) {
102 			sign = ' ';
103 			size--;
104 		}
105 	}
106 	if (type & SPECIAL) {
107 		if (base == 16)
108 			size -= 2;
109 		else if (base == 8)
110 			size--;
111 	}
112 	i = 0;
113 	if (num == 0)
114 		tmp[i++]='0';
115 	else while (num != 0) {
116 		tmp[i++] = digits[do_div(num, base)];
117 	}
118 	if (i > precision)
119 		precision = i;
120 	size -= precision;
121 	if (!(type&(ZEROPAD+LEFT)))
122 		while(size-->0)
123 			*str++ = ' ';
124 	if (sign)
125 		*str++ = sign;
126 	if (type & SPECIAL) {
127 		if (base==8)
128 			*str++ = '0';
129 		else if (base==16) {
130 			*str++ = '0';
131 			*str++ = digits[33];
132 		}
133 	}
134 	if (!(type & LEFT))
135 		while (size-- > 0)
136 			*str++ = c;
137 	while (i < precision--)
138 		*str++ = '0';
139 	while (i-- > 0)
140 		*str++ = tmp[i];
141 	while (size-- > 0)
142 		*str++ = ' ';
143 	return str;
144 }
145 
vsprintf(char * buf,const char * fmt,va_list args)146 int vsprintf(char *buf, const char *fmt, va_list args)
147 {
148 	int len;
149 	unsigned long long num;
150 	int i, base;
151 	char * str;
152 	const char *s;
153 
154 	int flags;		/* flags to number() */
155 
156 	int field_width;	/* width of output field */
157 	int precision;		/* min. # of digits for integers; max
158 				   number of chars for from string */
159 	int qualifier;		/* 'h', 'l', or 'L' for integer fields */
160 	                        /* 'z' support added 23/7/1999 S.H.    */
161 				/* 'z' changed to 'Z' --davidm 1/25/99 */
162 
163 
164 	for (str=buf ; *fmt ; ++fmt) {
165 		if (*fmt != '%') {
166 			*str++ = *fmt;
167 			continue;
168 		}
169 
170 		/* process flags */
171 		flags = 0;
172 		repeat:
173 			++fmt;		/* this also skips first '%' */
174 			switch (*fmt) {
175 				case '-': flags |= LEFT; goto repeat;
176 				case '+': flags |= PLUS; goto repeat;
177 				case ' ': flags |= SPACE; goto repeat;
178 				case '#': flags |= SPECIAL; goto repeat;
179 				case '0': flags |= ZEROPAD; goto repeat;
180 				}
181 
182 		/* get field width */
183 		field_width = -1;
184 		if ('0' <= *fmt && *fmt <= '9')
185 			field_width = skip_atoi(&fmt);
186 		else if (*fmt == '*') {
187 			++fmt;
188 			/* it's the next argument */
189 			field_width = va_arg(args, int);
190 			if (field_width < 0) {
191 				field_width = -field_width;
192 				flags |= LEFT;
193 			}
194 		}
195 
196 		/* get the precision */
197 		precision = -1;
198 		if (*fmt == '.') {
199 			++fmt;
200 			if ('0' <= *fmt && *fmt <= '9')
201 				precision = skip_atoi(&fmt);
202 			else if (*fmt == '*') {
203 				++fmt;
204 				/* it's the next argument */
205 				precision = va_arg(args, int);
206 			}
207 			if (precision < 0)
208 				precision = 0;
209 		}
210 
211 		/* get the conversion qualifier */
212 		qualifier = -1;
213 		if (*fmt == 'l' && *(fmt + 1) == 'l') {
214 			qualifier = 'q';
215 			fmt += 2;
216 		} else if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L'
217 			|| *fmt == 'Z') {
218 			qualifier = *fmt;
219 			++fmt;
220 		}
221 
222 		/* default base */
223 		base = 10;
224 
225 		switch (*fmt) {
226 		case 'c':
227 			if (!(flags & LEFT))
228 				while (--field_width > 0)
229 					*str++ = ' ';
230 			*str++ = (unsigned char) va_arg(args, int);
231 			while (--field_width > 0)
232 				*str++ = ' ';
233 			continue;
234 
235 		case 's':
236 			s = va_arg(args, char *);
237 			if (!s)
238 				s = "<NULL>";
239 
240 			len = strnlen(s, precision);
241 
242 			if (!(flags & LEFT))
243 				while (len < field_width--)
244 					*str++ = ' ';
245 			for (i = 0; i < len; ++i)
246 				*str++ = *s++;
247 			while (len < field_width--)
248 				*str++ = ' ';
249 			continue;
250 
251 		case 'p':
252 			if (field_width == -1) {
253 				field_width = 2*sizeof(void *);
254 				flags |= ZEROPAD;
255 			}
256 			str = number(str,
257 				(unsigned long) va_arg(args, void *), 16,
258 				field_width, precision, flags);
259 			continue;
260 
261 
262 		case 'n':
263 			if (qualifier == 'l') {
264 				long * ip = va_arg(args, long *);
265 				*ip = (str - buf);
266 			} else if (qualifier == 'Z') {
267 				size_t * ip = va_arg(args, size_t *);
268 				*ip = (str - buf);
269 			} else {
270 				int * ip = va_arg(args, int *);
271 				*ip = (str - buf);
272 			}
273 			continue;
274 
275 		case '%':
276 			*str++ = '%';
277 			continue;
278 
279 		/* integer number formats - set up the flags and "break" */
280 		case 'o':
281 			base = 8;
282 			break;
283 
284 		case 'X':
285 			flags |= LARGE;
286 		case 'x':
287 			base = 16;
288 			break;
289 
290 		case 'd':
291 		case 'i':
292 			flags |= SIGN;
293 		case 'u':
294 			break;
295 
296 		default:
297 			*str++ = '%';
298 			if (*fmt)
299 				*str++ = *fmt;
300 			else
301 				--fmt;
302 			continue;
303 		}
304 		if (qualifier == 'l') {
305 			num = va_arg(args, unsigned long);
306 			if (flags & SIGN)
307 				num = (signed long) num;
308 		} else if (qualifier == 'q') {
309 			num = va_arg(args, unsigned long long);
310 			if (flags & SIGN)
311 				num = (signed long long) num;
312 		} else if (qualifier == 'Z') {
313 			num = va_arg(args, size_t);
314 		} else if (qualifier == 'h') {
315 			num = (unsigned short) va_arg(args, int);
316 			if (flags & SIGN)
317 				num = (signed short) num;
318 		} else {
319 			num = va_arg(args, unsigned int);
320 			if (flags & SIGN)
321 				num = (signed int) num;
322 		}
323 		str = number(str, num, base, field_width, precision, flags);
324 	}
325 	*str = '\0';
326 	return str-buf;
327 }
328 
sprintf(char * buf,const char * fmt,...)329 int sprintf(char * buf, const char *fmt, ...)
330 {
331 	va_list args;
332 	int i;
333 
334 	va_start(args, fmt);
335 	i=vsprintf(buf,fmt,args);
336 	va_end(args);
337 	return i;
338 }
339 
340 static char sprint_buf[1024];
341 
342 int
printf(const char * fmt,...)343 printf(const char *fmt, ...)
344 {
345 	va_list args;
346 	int n;
347 
348 	va_start(args, fmt);
349 	n = vsprintf(sprint_buf, fmt, args);
350 	va_end(args);
351 	if (console_ops.write)
352 		console_ops.write(sprint_buf, n);
353 	return n;
354 }
355