blob: 6e2a1aceffcf44bdcef3db9c4d3c621760a1c730 [file] [log] [blame]
Achin Gupta4f6ad662013-10-25 09:08:21 +01001/*-
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-2013, ARM Ltd. All rights reserved.
39 * ---------------------------------------------------------------
40 * File: lib/subr_prf.c
41 */
42
43/*
44#include "types.h"
45#include "varargs.h"
46#include "ctype.h"
47#include "string.h"
48*/
49#include <stddef.h>
50#include <sys/types.h> /* For ssize_t */
51#include <stdint.h>
52#include <string.h>
53
54#include "ctype.h"
55
56typedef uint64_t uintmax_t;
57typedef int64_t intmax_t;
58typedef unsigned char u_char;
59typedef unsigned int u_int;
60typedef int64_t quad_t;
61typedef uint64_t u_quad_t;
62typedef unsigned long u_long;
63typedef unsigned short u_short;
64
65static inline int imax(int a, int b) { return (a > b ? a : b); }
66
67/*
68 * Note that stdarg.h and the ANSI style va_start macro is used for both
69 * ANSI and traditional C compilers.
70 */
71
72#define TOCONS 0x01
73#define TOTTY 0x02
74#define TOLOG 0x04
75
76/* Max number conversion buffer length: a u_quad_t in base 2, plus NUL byte. */
77#define MAXNBUF (sizeof(intmax_t) * 8 + 1)
78
79struct putchar_arg {
80 int flags;
81 int pri;
82 struct tty *tty;
83 char *p_bufr;
84 size_t n_bufr;
85 char *p_next;
86 size_t remain;
87};
88
89struct snprintf_arg {
90 char *str;
91 size_t remain;
92};
93
94extern int log_open;
95
96static char *ksprintn(char *nbuf, uintmax_t num, int base, int *len, int upper);
97static void snprintf_func(int ch, void *arg);
98static int kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap);
99
100int vsnprintf(char *str, size_t size, const char *format, va_list ap);
101
102static char const hex2ascii_data[] = "0123456789abcdefghijklmnopqrstuvwxyz";
103#define hex2ascii(hex) (hex2ascii_data[hex])
104
105/*
106 * Scaled down version of sprintf(3).
107 */
108int
109sprintf(char *buf, const char *cfmt, ...)
110{
111 int retval;
112 va_list ap;
113
114 va_start(ap, cfmt);
115 retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
116 buf[retval] = '\0';
117 va_end(ap);
118 return (retval);
119}
120
121/*
122 * Scaled down version of vsprintf(3).
123 */
124int
125vsprintf(char *buf, const char *cfmt, va_list ap)
126{
127 int retval;
128
129 retval = kvprintf(cfmt, NULL, (void *)buf, 10, ap);
130 buf[retval] = '\0';
131 return (retval);
132}
133
134/*
135 * Scaled down version of snprintf(3).
136 */
137int
138snprintf(char *str, size_t size, const char *format, ...)
139{
140 int retval;
141 va_list ap;
142
143 va_start(ap, format);
144 retval = vsnprintf(str, size, format, ap);
145 va_end(ap);
146 return(retval);
147}
148
149/*
150 * Scaled down version of vsnprintf(3).
151 */
152int
153vsnprintf(char *str, size_t size, const char *format, va_list ap)
154{
155 struct snprintf_arg info;
156 int retval;
157
158 info.str = str;
159 info.remain = size;
160 retval = kvprintf(format, snprintf_func, &info, 10, ap);
161 if (info.remain >= 1)
162 *info.str++ = '\0';
163 return (retval);
164}
165
166static void
167snprintf_func(int ch, void *arg)
168{
169 struct snprintf_arg *const info = arg;
170
171 if (info->remain >= 2) {
172 *info->str++ = ch;
173 info->remain--;
174 }
175}
176
177
178/*
179 * Kernel version which takes radix argument vsnprintf(3).
180 */
181int
182vsnrprintf(char *str, size_t size, int radix, const char *format, va_list ap)
183{
184 struct snprintf_arg info;
185 int retval;
186
187 info.str = str;
188 info.remain = size;
189 retval = kvprintf(format, snprintf_func, &info, radix, ap);
190 if (info.remain >= 1)
191 *info.str++ = '\0';
192 return (retval);
193}
194
195
196/*
197 * Put a NUL-terminated ASCII number (base <= 36) in a buffer in reverse
198 * order; return an optional length and a pointer to the last character
199 * written in the buffer (i.e., the first character of the string).
200 * The buffer pointed to by `nbuf' must have length >= MAXNBUF.
201 */
202static char *
203ksprintn(char *nbuf, uintmax_t num, int base, int *lenp, int upper)
204{
205 char *p, c;
206
207 p = nbuf;
208 *p = '\0';
209 do {
210 c = hex2ascii(num % base);
211 *++p = upper ? toupper(c) : c;
212 } while (num /= base);
213 if (lenp)
214 *lenp = p - nbuf;
215 return (p);
216}
217
218/*
219 * Scaled down version of printf(3).
220 *
221 * Two additional formats:
222 *
223 * The format %b is supported to decode error registers.
224 * Its usage is:
225 *
226 * printf("reg=%b\n", regval, "<base><arg>*");
227 *
228 * where <base> is the output base expressed as a control character, e.g.
229 * \10 gives octal; \20 gives hex. Each arg is a sequence of characters,
230 * the first of which gives the bit number to be inspected (origin 1), and
231 * the next characters (up to a control character, i.e. a character <= 32),
232 * give the name of the register. Thus:
233 *
234 * kvprintf("reg=%b\n", 3, "\10\2BITTWO\1BITONE\n");
235 *
236 * would produce output:
237 *
238 * reg=3<BITTWO,BITONE>
239 *
240 * XXX: %D -- Hexdump, takes pointer and separator string:
241 * ("%6D", ptr, ":") -> XX:XX:XX:XX:XX:XX
242 * ("%*D", len, ptr, " " -> XX XX XX XX ...
243 */
244int
245kvprintf(char const *fmt, void (*func)(int, void*), void *arg, int radix, va_list ap)
246{
247#define PCHAR(c) {int cc=(c); if (func) (*func)(cc,arg); else *d++ = cc; retval++; }
248 char nbuf[MAXNBUF];
249 char *d;
250 const char *p, *percent, *q;
251 u_char *up;
252 int ch, n;
253 uintmax_t num;
254 int base, lflag, qflag, tmp, width, ladjust, sharpflag, neg, sign, dot;
255 int cflag, hflag, jflag, tflag, zflag;
256 int dwidth, upper;
257 char padc;
258 int stop = 0, retval = 0;
259
260 num = 0;
261 if (!func)
262 d = (char *) arg;
263 else
264 d = NULL;
265
266 if (fmt == NULL)
267 fmt = "(fmt null)\n";
268
269 if (radix < 2 || radix > 36)
270 radix = 10;
271
272 for (;;) {
273 padc = ' ';
274 width = 0;
275 while ((ch = (u_char)*fmt++) != '%' || stop) {
276 if (ch == '\0')
277 return (retval);
278 PCHAR(ch);
279 }
280 percent = fmt - 1;
281 qflag = 0; lflag = 0; ladjust = 0; sharpflag = 0; neg = 0;
282 sign = 0; dot = 0; dwidth = 0; upper = 0;
283 cflag = 0; hflag = 0; jflag = 0; tflag = 0; zflag = 0;
284reswitch: switch (ch = (u_char)*fmt++) {
285 case '.':
286 dot = 1;
287 goto reswitch;
288 case '#':
289 sharpflag = 1;
290 goto reswitch;
291 case '+':
292 sign = 1;
293 goto reswitch;
294 case '-':
295 ladjust = 1;
296 goto reswitch;
297 case '%':
298 PCHAR(ch);
299 break;
300 case '*':
301 if (!dot) {
302 width = va_arg(ap, int);
303 if (width < 0) {
304 ladjust = !ladjust;
305 width = -width;
306 }
307 } else {
308 dwidth = va_arg(ap, int);
309 }
310 goto reswitch;
311 case '0':
312 if (!dot) {
313 padc = '0';
314 goto reswitch;
315 }
316 case '1': case '2': case '3': case '4':
317 case '5': case '6': case '7': case '8': case '9':
318 for (n = 0;; ++fmt) {
319 n = n * 10 + ch - '0';
320 ch = *fmt;
321 if (ch < '0' || ch > '9')
322 break;
323 }
324 if (dot)
325 dwidth = n;
326 else
327 width = n;
328 goto reswitch;
329 case 'b':
330 num = (u_int)va_arg(ap, int);
331 p = va_arg(ap, char *);
332 for (q = ksprintn(nbuf, num, *p++, NULL, 0); *q;)
333 PCHAR(*q--);
334
335 if (num == 0)
336 break;
337
338 for (tmp = 0; *p;) {
339 n = *p++;
340 if (num & (1 << (n - 1))) {
341 PCHAR(tmp ? ',' : '<');
342 for (; (n = *p) > ' '; ++p)
343 PCHAR(n);
344 tmp = 1;
345 } else
346 for (; *p > ' '; ++p)
347 continue;
348 }
349 if (tmp)
350 PCHAR('>');
351 break;
352 case 'c':
353 PCHAR(va_arg(ap, int));
354 break;
355 case 'D':
356 up = va_arg(ap, u_char *);
357 p = va_arg(ap, char *);
358 if (!width)
359 width = 16;
360 while(width--) {
361 PCHAR(hex2ascii(*up >> 4));
362 PCHAR(hex2ascii(*up & 0x0f));
363 up++;
364 if (width)
365 for (q=p;*q;q++)
366 PCHAR(*q);
367 }
368 break;
369 case 'd':
370 case 'i':
371 base = 10;
372 sign = 1;
373 goto handle_sign;
374 case 'h':
375 if (hflag) {
376 hflag = 0;
377 cflag = 1;
378 } else
379 hflag = 1;
380 goto reswitch;
381 case 'j':
382 jflag = 1;
383 goto reswitch;
384 case 'l':
385 if (lflag) {
386 lflag = 0;
387 qflag = 1;
388 } else
389 lflag = 1;
390 goto reswitch;
391 case 'n':
392 if (jflag)
393 *(va_arg(ap, intmax_t *)) = retval;
394 else if (qflag)
395 *(va_arg(ap, quad_t *)) = retval;
396 else if (lflag)
397 *(va_arg(ap, long *)) = retval;
398 else if (zflag)
399 *(va_arg(ap, size_t *)) = retval;
400 else if (hflag)
401 *(va_arg(ap, short *)) = retval;
402 else if (cflag)
403 *(va_arg(ap, char *)) = retval;
404 else
405 *(va_arg(ap, int *)) = retval;
406 break;
407 case 'o':
408 base = 8;
409 goto handle_nosign;
410 case 'p':
411 base = 16;
412 sharpflag = (width == 0);
413 sign = 0;
414 num = (uintptr_t)va_arg(ap, void *);
415 goto number;
416 case 'q':
417 qflag = 1;
418 goto reswitch;
419 case 'r':
420 base = radix;
421 if (sign)
422 goto handle_sign;
423 goto handle_nosign;
424 case 's':
425 p = va_arg(ap, char *);
426 if (p == NULL)
427 p = "(null)";
428 if (!dot)
429 n = strlen (p);
430 else
431 for (n = 0; n < dwidth && p[n]; n++)
432 continue;
433
434 width -= n;
435
436 if (!ladjust && width > 0)
437 while (width--)
438 PCHAR(padc);
439 while (n--)
440 PCHAR(*p++);
441 if (ladjust && width > 0)
442 while (width--)
443 PCHAR(padc);
444 break;
445 case 't':
446 tflag = 1;
447 goto reswitch;
448 case 'u':
449 base = 10;
450 goto handle_nosign;
451 case 'X':
452 upper = 1;
453 case 'x':
454 base = 16;
455 goto handle_nosign;
456 case 'y':
457 base = 16;
458 sign = 1;
459 goto handle_sign;
460 case 'z':
461 zflag = 1;
462 goto reswitch;
463handle_nosign:
464 sign = 0;
465 if (jflag)
466 num = va_arg(ap, uintmax_t);
467 else if (qflag)
468 num = va_arg(ap, u_quad_t);
469 else if (tflag)
470 num = va_arg(ap, ptrdiff_t);
471 else if (lflag)
472 num = va_arg(ap, u_long);
473 else if (zflag)
474 num = va_arg(ap, size_t);
475 else if (hflag)
476 num = (u_short)va_arg(ap, int);
477 else if (cflag)
478 num = (u_char)va_arg(ap, int);
479 else
480 num = va_arg(ap, u_int);
481 goto number;
482handle_sign:
483 if (jflag)
484 num = va_arg(ap, intmax_t);
485 else if (qflag)
486 num = va_arg(ap, quad_t);
487 else if (tflag)
488 num = va_arg(ap, ptrdiff_t);
489 else if (lflag)
490 num = va_arg(ap, long);
491 else if (zflag)
492 num = va_arg(ap, ssize_t);
493 else if (hflag)
494 num = (short)va_arg(ap, int);
495 else if (cflag)
496 num = (char)va_arg(ap, int);
497 else
498 num = va_arg(ap, int);
499number:
500 if (sign && (intmax_t)num < 0) {
501 neg = 1;
502 num = -(intmax_t)num;
503 }
504 p = ksprintn(nbuf, num, base, &n, upper);
505 tmp = 0;
506 if (sharpflag && num != 0) {
507 if (base == 8)
508 tmp++;
509 else if (base == 16)
510 tmp += 2;
511 }
512 if (neg)
513 tmp++;
514
515 if (!ladjust && padc == '0')
516 dwidth = width - tmp;
517 width -= tmp + imax(dwidth, n);
518 dwidth -= n;
519 if (!ladjust)
520 while (width-- > 0)
521 PCHAR(' ');
522 if (neg)
523 PCHAR('-');
524 if (sharpflag && num != 0) {
525 if (base == 8) {
526 PCHAR('0');
527 } else if (base == 16) {
528 PCHAR('0');
529 PCHAR('x');
530 }
531 }
532 while (dwidth-- > 0)
533 PCHAR('0');
534
535 while (*p)
536 PCHAR(*p--);
537
538 if (ladjust)
539 while (width-- > 0)
540 PCHAR(' ');
541
542 break;
543 default:
544 while (percent < fmt)
545 PCHAR(*percent++);
546 /*
547 * Since we ignore an formatting argument it is no
548 * longer safe to obey the remaining formatting
549 * arguments as the arguments will no longer match
550 * the format specs.
551 */
552 stop = 1;
553 break;
554 }
555 }
556#undef PCHAR
557}