8 /* Auxiliary data for vsnprintf_helper(). */
11 char *p; /* Current output position. */
12 int length; /* Length of output string. */
13 int max_length; /* Max length of output string. */
16 static void vsnprintf_helper (char, void *);
18 /* Like vprintf(), except that output is stored into BUFFER,
19 which must have space for BUF_SIZE characters. Writes at most
20 BUF_SIZE - 1 characters to BUFFER, followed by a null
21 terminator. BUFFER will always be null-terminated unless
22 BUF_SIZE is zero. Returns the number of characters that would
23 have been written to BUFFER, not including a null terminator,
24 had there been enough room. */
26 vsnprintf (char *buffer, size_t buf_size, const char *format, va_list args)
28 /* Set up aux data for vsnprintf_helper(). */
29 struct vsnprintf_aux aux;
32 aux.max_length = buf_size > 0 ? buf_size - 1 : 0;
34 /* Do most of the work. */
35 __vprintf (format, args, vsnprintf_helper, &aux);
37 /* Add null terminator. */
44 /* Helper function for vsnprintf(). */
46 vsnprintf_helper (char ch, void *aux_)
48 struct vsnprintf_aux *aux = aux_;
50 if (aux->length++ < aux->max_length)
54 /* Like printf(), except that output is stored into BUFFER,
55 which must have space for BUF_SIZE characters. Writes at most
56 BUF_SIZE - 1 characters to BUFFER, followed by a null
57 terminator. BUFFER will always be null-terminated unless
58 BUF_SIZE is zero. Returns the number of characters that would
59 have been written to BUFFER, not including a null terminator,
60 had there been enough room. */
62 snprintf (char *buffer, size_t buf_size, const char *format, ...)
67 va_start (args, format);
68 retval = vsnprintf (buffer, buf_size, format, args);
74 /* Writes formatted output to the console.
75 In the kernel, the console is both the video display and first
77 In userspace, the console is file descriptor 1.
80 printf (const char *format, ...)
85 va_start (args, format);
86 retval = vprintf (format, args);
92 /* printf() formatting internals. */
94 /* A printf() conversion. */
95 struct printf_conversion
100 MINUS = 1 << 0, /* '-' */
101 PLUS = 1 << 1, /* '+' */
102 SPACE = 1 << 2, /* ' ' */
103 POUND = 1 << 3, /* '#' */
104 ZERO = 1 << 4, /* '0' */
105 GROUP = 1 << 5 /* '\'' */
109 /* Minimum field width. */
112 /* Numeric precision.
113 -1 indicates no precision was specified. */
116 /* Type of argument to format. */
121 INT = 3, /* (none) */
124 LONGLONG = 6, /* ll */
125 PTRDIFFT = 7, /* t */
133 int base; /* Base. */
134 const char *digits; /* Collection of digits. */
135 const char *signifier; /* Prefix used with # flag. */
136 int group; /* Number of digits to group with ' flag. */
139 static const struct integer_base base_d = {10, "0123456789", "", 3};
140 static const struct integer_base base_o = {8, "01234567", "0", 3};
141 static const struct integer_base base_x = {16, "0123456789abcdef", "0x", 4};
142 static const struct integer_base base_X = {16, "0123456789ABCDEF", "0X", 4};
144 static const char *parse_conversion (const char *format,
145 struct printf_conversion *,
147 static void format_integer (uintmax_t value, bool is_signed, bool negative,
148 const struct integer_base *,
149 const struct printf_conversion *,
150 void (*output) (char, void *), void *aux);
151 static void output_dup (char ch, size_t cnt,
152 void (*output) (char, void *), void *aux);
153 static void format_string (const char *string, size_t length,
154 struct printf_conversion *,
155 void (*output) (char, void *), void *aux);
158 __vprintf (const char *format, va_list args,
159 void (*output) (char, void *), void *aux)
161 for (; *format != '\0'; format++)
163 struct printf_conversion c;
165 /* Literally copy non-conversions to output. */
168 output (*format, aux);
180 /* Parse conversion specifiers. */
181 format = parse_conversion (format, &c, &args);
189 /* Signed integer conversions. */
195 value = (signed char) va_arg (args, int);
198 value = (short) va_arg (args, int);
201 value = va_arg (args, int);
204 value = va_arg (args, intmax_t);
207 value = va_arg (args, long);
210 value = va_arg (args, long long);
213 value = va_arg (args, ptrdiff_t);
216 value = va_arg (args, size_t);
222 format_integer (value < 0 ? -value : value,
223 true, value < 0, &base_d, &c, output, aux);
232 /* Unsigned integer conversions. */
234 const struct integer_base *b;
239 value = (unsigned char) va_arg (args, unsigned);
242 value = (unsigned short) va_arg (args, unsigned);
245 value = va_arg (args, unsigned);
248 value = va_arg (args, uintmax_t);
251 value = va_arg (args, unsigned long);
254 value = va_arg (args, unsigned long long);
257 value = va_arg (args, ptrdiff_t);
260 value = va_arg (args, size_t);
268 case 'o': b = &base_o; break;
269 case 'u': b = &base_d; break;
270 case 'x': b = &base_x; break;
271 case 'X': b = &base_X; break;
272 default: NOT_REACHED ();
275 format_integer (value, false, false, b, &c, output, aux);
281 /* Treat character as single-character string. */
282 char ch = va_arg (args, int);
283 format_string (&ch, 1, &c, output, aux);
289 /* String conversion. */
290 const char *s = va_arg (args, char *);
294 /* Limit string length according to precision.
295 Note: if c.precision == -1 then strnlen() will get
296 SIZE_MAX for MAXLEN, which is just what we want. */
297 format_string (s, strnlen (s, c.precision), &c, output, aux);
303 /* Pointer conversion.
304 Format pointers as %#x. */
305 void *p = va_arg (args, void *);
308 format_integer ((uintptr_t) p, false, false,
309 &base_x, &c, output, aux);
319 /* We don't support floating-point arithmetic,
320 and %n can be part of a security hole. */
321 __printf ("<<no %%%c in kernel>>", output, aux, *format);
325 __printf ("<<no %%%c conversion>>", output, aux, *format);
331 /* Parses conversion option characters starting at FORMAT and
332 initializes C appropriately. Returns the character in FORMAT
333 that indicates the conversion (e.g. the `d' in `%d'). Uses
334 *ARGS for `*' field widths and precisions. */
336 parse_conversion (const char *format, struct printf_conversion *c,
339 /* Parse flag characters. */
369 if (c->flags & MINUS)
374 /* Parse field width. */
379 c->width = va_arg (*args, int);
383 for (; isdigit (*format); format++)
384 c->width = c->width * 10 + *format - '0';
388 c->width = -c->width;
392 /* Parse precision. */
400 c->precision = va_arg (*args, int);
405 for (; isdigit (*format); format++)
406 c->precision = c->precision * 10 + *format - '0';
408 if (c->precision < 0)
411 if (c->precision >= 0)
458 /* Performs an integer conversion, writing output to OUTPUT with
459 auxiliary data AUX. The integer converted has absolute value
460 VALUE. If IS_SIGNED is true, does a signed conversion with
461 NEGATIVE indicating a negative value; otherwise does an
462 unsigned conversion and ignores IS_SIGNED. The output will
463 use the given DIGITS, with strlen(DIGITS) indicating the
464 output base. Details of the conversion are in C. */
466 format_integer (uintmax_t value, bool is_signed, bool negative,
467 const struct integer_base *b,
468 const struct printf_conversion *c,
469 void (*output) (char, void *), void *aux)
471 char buf[64], *cp; /* Buffer and current position. */
472 const char *signifier; /* b->signifier or "". */
473 int precision; /* Rendered precision. */
474 int pad_cnt; /* # of pad characters to fill field width. */
475 int digit_cnt; /* # of digits output so far. */
477 /* Accumulate digits into buffer.
478 This algorithm produces digits in reverse order, so later we
479 will output the buffer's content in reverse. This is also
480 the reason that later we append zeros and the sign. */
485 if ((c->flags & GROUP) && digit_cnt > 0 && digit_cnt % b->group == 0)
487 *cp++ = b->digits[value % b->base];
492 /* Append enough zeros to match precision.
493 If requested precision is 0, then a value of zero is
494 rendered as a null string, otherwise as "0". */
495 precision = c->precision < 0 ? 1 : c->precision;
496 while (cp - buf < precision && cp - buf < (int) sizeof buf - 8)
503 *cp++ = negative ? '-' : '+';
504 else if (c->flags & SPACE)
505 *cp++ = negative ? '-' : ' ';
510 /* Calculate number of pad characters to fill field width. */
511 signifier = c->flags & POUND ? b->signifier : "";
512 pad_cnt = c->width - (cp - buf) - strlen (signifier);
517 if ((c->flags & (MINUS | ZERO)) == 0)
518 output_dup (' ', pad_cnt, output, aux);
519 while (*signifier != '\0')
520 output (*signifier++, aux);
522 output_dup ('0', pad_cnt, output, aux);
525 if (c->flags & MINUS)
526 output_dup (' ', pad_cnt, output, aux);
529 /* Writes CH to OUTPUT with auxiliary data AUX, CNT times. */
531 output_dup (char ch, size_t cnt, void (*output) (char, void *), void *aux)
537 /* Formats the LENGTH characters starting at STRING according to
538 the conversion specified in C. Writes output to OUTPUT with
539 auxiliary data AUX. */
541 format_string (const char *string, size_t length,
542 struct printf_conversion *c,
543 void (*output) (char, void *), void *aux)
545 if (c->width > 1 && (c->flags & MINUS) == 0)
546 output_dup (' ', c->width - 1, output, aux);
548 output (*string++, aux);
549 if (c->width > 1 && (c->flags & MINUS) != 0)
550 output_dup (' ', c->width - 1, output, aux);
553 /* Wrapper for __vprintf() that converts varargs into a
556 __printf (const char *format,
557 void (*output) (char, void *), void *aux, ...)
561 va_start (args, aux);
562 __vprintf (format, args, output, aux);
566 /* Dumps the SIZE bytes in BUF to the console as hex bytes
567 arranged 16 per line. Numeric offsets are also included,
568 starting at OFS for the first byte in BUF. If ASCII is true
569 then the corresponding ASCII characters are also rendered
572 hex_dump (uintptr_t ofs, const void *buf_, size_t size, bool ascii)
574 const uint8_t *buf = buf_;
575 const size_t per_line = 16; /* Maximum bytes per line. */
579 size_t start, end, n;
582 /* Number of bytes on this line. */
583 start = ofs % per_line;
585 if (end - start > size)
590 printf ("%08jx ", (uintmax_t) ROUND_DOWN (ofs, per_line));
591 for (i = 0; i < start; i++)
595 buf[i - start], i == per_line / 2 - 1? '-' : ' ');
598 for (; i < per_line; i++)
601 for (i = 0; i < start; i++)
605 isprint (buf[i - start]) ? buf[i - start] : '.');
606 for (; i < per_line; i++)