• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*-
2  * Copyright (c) 1986, 1988, 1991, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  * (c) UNIX System Laboratories, Inc.
5  * All or some portions of this file are derived from material licensed
6  * to the University of California by American Telephone and Telegraph
7  * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8  * the permission of UNIX System Laboratories, Inc.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 4. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  *
34  *	@(#)subr_prf.c	8.3 (Berkeley) 1/21/94
35  */
36 
37 /*
38  * Portions copyright (c) 2009-2014, ARM Limited and Contributors.
39  * All rights reserved.
40  */
41 
42 #include <stdio.h>
43 #include <stdint.h>
44 #include <stdarg.h>
45 #include <stddef.h>
46 #include <string.h>
47 #include <ctype.h>
48 
49 typedef unsigned char u_char;
50 typedef unsigned int u_int;
51 typedef int64_t quad_t;
52 typedef uint64_t u_quad_t;
53 typedef unsigned long u_long;
54 typedef unsigned short u_short;
55 
imax(int a,int b)56 static inline int imax(int a, int b) { return (a > b ? a : b); }
57 
58 /*
59  * Note that stdarg.h and the ANSI style va_start macro is used for both
60  * ANSI and traditional C compilers.
61  */
62 
63 #define TOCONS	0x01
64 #define TOTTY	0x02
65 #define TOLOG	0x04
66 
67 /* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
68 #define MAXNBUF	(sizeof(intmax_t) * 8 + 1)
69 
70 struct putchar_arg {
71 	int	flags;
72 	int	pri;
73 	struct	tty *tty;
74 	char	*p_bufr;
75 	size_t	n_bufr;
76 	char	*p_next;
77 	size_t	remain;
78 };
79 
80 struct snprintf_arg {
81 	char	*str;
82 	size_t	remain;
83 };
84 
85 extern	int log_open;
86 
87 static char *ksprintn(char *nbuf, uintmax_t num, int base, int *len, int upper);
88 static void  snprintf_func(int ch, void *arg);
89 static int kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap);
90 
91 int vsnprintf(char *str, size_t size, const char *format, va_list ap);
92 
93 static char const hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz";
94 #define hex2ascii(hex) (hex2ascii_data[hex])
95 
96 /*
97  * Scaled down version of sprintf(3).
98  */
99 int
sprintf(char * buf,const char * cfmt,...)100 sprintf(char *buf, const char *cfmt, ...)
101 {
102 	int retval;
103 	va_list ap;
104 
105 	va_start(ap, cfmt);
106 	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
107 	buf[retval] = '\0';
108 	va_end(ap);
109 	return (retval);
110 }
111 
112 /*
113  * Scaled down version of vsprintf(3).
114  */
115 int
vsprintf(char * buf,const char * cfmt,va_list ap)116 vsprintf(char *buf, const char *cfmt, va_list ap)
117 {
118 	int retval;
119 
120 	retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
121 	buf[retval] = '\0';
122 	return (retval);
123 }
124 
125 /*
126  * Scaled down version of snprintf(3).
127  */
128 int
snprintf(char * str,size_t size,const char * format,...)129 snprintf(char *str, size_t size, const char *format, ...)
130 {
131 	int retval;
132 	va_list ap;
133 
134 	va_start(ap, format);
135 	retval = vsnprintf(str, size, format, ap);
136 	va_end(ap);
137 	return(retval);
138 }
139 
140 /*
141  * Scaled down version of vsnprintf(3).
142  */
143 int
vsnprintf(char * str,size_t size,const char * format,va_list ap)144 vsnprintf(char *str, size_t size, const char *format, va_list ap)
145 {
146 	struct snprintf_arg info;
147 	int retval;
148 
149 	info.str = str;
150 	info.remain = size;
151 	retval = kvprintf(format, snprintf_func, &info, 10, ap);
152 	if (info.remain >= 1)
153 		*info.str++ = '\0';
154 	return (retval);
155 }
156 
157 static void
snprintf_func(int ch,void * arg)158 snprintf_func(int ch, void *arg)
159 {
160 	struct snprintf_arg *const info = arg;
161 
162 	if (info->remain >= 2) {
163 		*info->str++ = ch;
164 		info->remain--;
165 	}
166 }
167 
168 
169 /*
170  * Kernel version which takes radix argument vsnprintf(3).
171  */
172 int
vsnrprintf(char * str,size_t size,int radix,const char * format,va_list ap)173 vsnrprintf(char *str, size_t size, int radix, const char *format, va_list ap)
174 {
175 	struct snprintf_arg info;
176 	int retval;
177 
178 	info.str = str;
179 	info.remain = size;
180 	retval = kvprintf(format, snprintf_func, &info, radix, ap);
181 	if (info.remain >= 1)
182 		*info.str++ = '\0';
183 	return (retval);
184 }
185 
186 
187 /*
188  * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
189  * order; return an optional length and a pointer to the last character
190  * written in the buffer (i.e., the first character of the string).
191  * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
192  */
193 static char *
ksprintn(char * nbuf,uintmax_t num,int base,int * lenp,int upper)194 ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
195 {
196 	char *p, c;
197 
198 	p = nbuf;
199 	*p = '\0';
200 	do {
201 		c = hex2ascii(num % base);
202 		*++p = upper ? toupper(c) : c;
203 	} while (num /= base);
204 	if (lenp)
205 		*lenp = p - nbuf;
206 	return (p);
207 }
208 
209 /*
210  * Scaled down version of printf(3).
211  *
212  * Two additional formats:
213  *
214  * The format %b is supported to decode error registers.
215  * Its usage is:
216  *
217  *	printf("reg=%b\n", regval, "<base><arg>*");
218  *
219  * where <base> is the output base expressed as a control character, e.g.
220  * \10 gives octal; \20 gives hex.  Each arg is a sequence of characters,
221  * the first of which gives the bit number to be inspected (origin 1), and
222  * the next characters (up to a control character, i.e. a character <= 32),
223  * give the name of the register.  Thus:
224  *
225  *	kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
226  *
227  * would produce output:
228  *
229  *	reg=3<BITTWO,BITONE>
230  *
231  * XXX:  %D  -- Hexdump, takes pointer and separator string:
232  *		("%6D", ptr, ":")   -> XX:XX:XX:XX:XX:XX
233  *		("%*D", len, ptr, " " -> XX XX XX XX ...
234  */
235 int
kvprintf(char const * fmt,void (* func)(int,void *),void * arg,int radix,va_list ap)236 kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
237 {
238 #define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
239 	char nbuf[MAXNBUF];
240 	char *d;
241 	const char *p, *percent, *q;
242 	u_char *up;
243 	int ch, n;
244 	uintmax_t num;
245 	int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
246 	int cflag, hflag, jflag, tflag, zflag;
247 	int dwidth, upper;
248 	char padc;
249 	int stop = 0, retval = 0;
250 
251 	num = 0;
252 	if (!func)
253 		d = (char *) arg;
254 	else
255 		d = NULL;
256 
257 	if (fmt == NULL)
258 		fmt = "(fmt null)\n";
259 
260 	if (radix < 2 || radix > 36)
261 		radix = 10;
262 
263 	for (;;) {
264 		padc = ' ';
265 		width = 0;
266 		while ((ch = (u_char)*fmt++) != '%' || stop) {
267 			if (ch == '\0')
268 				return (retval);
269 			PCHAR(ch);
270 		}
271 		percent = fmt - 1;
272 		qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
273 		sign = 0; dot = 0; dwidth = 0; upper = 0;
274 		cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
275 reswitch:	switch (ch = (u_char)*fmt++) {
276 		case '.':
277 			dot = 1;
278 			goto reswitch;
279 		case '#':
280 			sharpflag = 1;
281 			goto reswitch;
282 		case '+':
283 			sign = 1;
284 			goto reswitch;
285 		case '-':
286 			ladjust = 1;
287 			goto reswitch;
288 		case '%':
289 			PCHAR(ch);
290 			break;
291 		case '*':
292 			if (!dot) {
293 				width = va_arg(ap, int);
294 				if (width < 0) {
295 					ladjust = !ladjust;
296 					width = -width;
297 				}
298 			} else {
299 				dwidth = va_arg(ap, int);
300 			}
301 			goto reswitch;
302 		case '0':
303 			if (!dot) {
304 				padc = '0';
305 				goto reswitch;
306 			}
307 		case '1': case '2': case '3': case '4':
308 		case '5': case '6': case '7': case '8': case '9':
309 				for (n = 0;; ++fmt) {
310 					n = n * 10 + ch - '0';
311 					ch = *fmt;
312 					if (ch < '0' || ch > '9')
313 						break;
314 				}
315 			if (dot)
316 				dwidth = n;
317 			else
318 				width = n;
319 			goto reswitch;
320 		case 'b':
321 			num = (u_int)va_arg(ap, int);
322 			p = va_arg(ap, char *);
323 			for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
324 				PCHAR(*q--);
325 
326 			if (num == 0)
327 				break;
328 
329 			for (tmp = 0; *p;) {
330 				n = *p++;
331 				if (num & (1 << (n - 1))) {
332 					PCHAR(tmp ? ',' : '<');
333 					for (; (n = *p) > ' '; ++p)
334 						PCHAR(n);
335 					tmp = 1;
336 				} else
337 					for (; *p > ' '; ++p)
338 						continue;
339 			}
340 			if (tmp)
341 				PCHAR('>');
342 			break;
343 		case 'c':
344 			PCHAR(va_arg(ap, int));
345 			break;
346 		case 'D':
347 			up = va_arg(ap, u_char *);
348 			p = va_arg(ap, char *);
349 			if (!width)
350 				width = 16;
351 			while(width--) {
352 				PCHAR(hex2ascii(*up >> 4));
353 				PCHAR(hex2ascii(*up & 0x0f));
354 				up++;
355 				if (width)
356 					for (q=p;*q;q++)
357 						PCHAR(*q);
358 			}
359 			break;
360 		case 'd':
361 		case 'i':
362 			base = 10;
363 			sign = 1;
364 			goto handle_sign;
365 		case 'h':
366 			if (hflag) {
367 				hflag = 0;
368 				cflag = 1;
369 			} else
370 				hflag = 1;
371 			goto reswitch;
372 		case 'j':
373 			jflag = 1;
374 			goto reswitch;
375 		case 'l':
376 			if (lflag) {
377 				lflag = 0;
378 				qflag = 1;
379 			} else
380 				lflag = 1;
381 			goto reswitch;
382 		case 'n':
383 			if (jflag)
384 				*(va_arg(ap, intmax_t *)) = retval;
385 			else if (qflag)
386 				*(va_arg(ap, quad_t *)) = retval;
387 			else if (lflag)
388 				*(va_arg(ap, long *)) = retval;
389 			else if (zflag)
390 				*(va_arg(ap, size_t *)) = retval;
391 			else if (hflag)
392 				*(va_arg(ap, short *)) = retval;
393 			else if (cflag)
394 				*(va_arg(ap, char *)) = retval;
395 			else
396 				*(va_arg(ap, int *)) = retval;
397 			break;
398 		case 'o':
399 			base = 8;
400 			goto handle_nosign;
401 		case 'p':
402 			base = 16;
403 			sharpflag = (width == 0);
404 			sign = 0;
405 			num = (uintptr_t)va_arg(ap, void *);
406 			goto number;
407 		case 'q':
408 			qflag = 1;
409 			goto reswitch;
410 		case 'r':
411 			base = radix;
412 			if (sign)
413 				goto handle_sign;
414 			goto handle_nosign;
415 		case 's':
416 			p = va_arg(ap, char *);
417 			if (p == NULL)
418 				p = "(null)";
419 			if (!dot)
420 				n = strlen (p);
421 			else
422 				for (n = 0; n < dwidth && p[n]; n++)
423 					continue;
424 
425 			width -= n;
426 
427 			if (!ladjust && width > 0)
428 				while (width--)
429 					PCHAR(padc);
430 			while (n--)
431 				PCHAR(*p++);
432 			if (ladjust && width > 0)
433 				while (width--)
434 					PCHAR(padc);
435 			break;
436 		case 't':
437 			tflag = 1;
438 			goto reswitch;
439 		case 'u':
440 			base = 10;
441 			goto handle_nosign;
442 		case 'X':
443 			upper = 1;
444 		case 'x':
445 			base = 16;
446 			goto handle_nosign;
447 		case 'y':
448 			base = 16;
449 			sign = 1;
450 			goto handle_sign;
451 		case 'z':
452 			zflag = 1;
453 			goto reswitch;
454 handle_nosign:
455 			sign = 0;
456 			if (jflag)
457 				num = va_arg(ap, uintmax_t);
458 			else if (qflag)
459 				num = va_arg(ap, u_quad_t);
460 			else if (tflag)
461 				num = va_arg(ap, ptrdiff_t);
462 			else if (lflag)
463 				num = va_arg(ap, u_long);
464 			else if (zflag)
465 				num = va_arg(ap, size_t);
466 			else if (hflag)
467 				num = (u_short)va_arg(ap, int);
468 			else if (cflag)
469 				num = (u_char)va_arg(ap, int);
470 			else
471 				num = va_arg(ap, u_int);
472 			goto number;
473 handle_sign:
474 			if (jflag)
475 				num = va_arg(ap, intmax_t);
476 			else if (qflag)
477 				num = va_arg(ap, quad_t);
478 			else if (tflag)
479 				num = va_arg(ap, ptrdiff_t);
480 			else if (lflag)
481 				num = va_arg(ap, long);
482 			else if (zflag)
483 				num = va_arg(ap, ssize_t);
484 			else if (hflag)
485 				num = (short)va_arg(ap, int);
486 			else if (cflag)
487 				num = (char)va_arg(ap, int);
488 			else
489 				num = va_arg(ap, int);
490 number:
491 			if (sign && (intmax_t)num < 0) {
492 				neg = 1;
493 				num = -(intmax_t)num;
494 			}
495 			p = ksprintn(nbuf, num, base, &n, upper);
496 			tmp = 0;
497 			if (sharpflag && num != 0) {
498 				if (base == 8)
499 					tmp++;
500 				else if (base == 16)
501 					tmp += 2;
502 			}
503 			if (neg)
504 				tmp++;
505 
506 			if (!ladjust && padc == '0')
507 				dwidth = width - tmp;
508 			width -= tmp + imax(dwidth, n);
509 			dwidth -= n;
510 			if (!ladjust)
511 				while (width-- > 0)
512 					PCHAR(' ');
513 			if (neg)
514 				PCHAR('-');
515 			if (sharpflag && num != 0) {
516 				if (base == 8) {
517 					PCHAR('0');
518 				} else if (base == 16) {
519 					PCHAR('0');
520 					PCHAR('x');
521 				}
522 			}
523 			while (dwidth-- > 0)
524 				PCHAR('0');
525 
526 			while (*p)
527 				PCHAR(*p--);
528 
529 			if (ladjust)
530 				while (width-- > 0)
531 					PCHAR(' ');
532 
533 			break;
534 		default:
535 			while (percent < fmt)
536 				PCHAR(*percent++);
537 			/*
538 			 * Since we ignore an formatting argument it is no
539 			 * longer safe to obey the remaining formatting
540 			 * arguments as the arguments will no longer match
541 			 * the format specs.
542 			 */
543 			stop = 1;
544 			break;
545 		}
546 	}
547 #undef PCHAR
548 }
549