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, int 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);
217 if (value > SIZE_MAX / 2)
218 value = value - SIZE_MAX - 1;
224 format_integer (value < 0 ? -value : value,
225 true, value < 0, &base_d, &c, output, aux);
234 /* Unsigned integer conversions. */
236 const struct integer_base *b;
241 value = (unsigned char) va_arg (args, unsigned);
244 value = (unsigned short) va_arg (args, unsigned);
247 value = va_arg (args, unsigned);
250 value = va_arg (args, uintmax_t);
253 value = va_arg (args, unsigned long);
256 value = va_arg (args, unsigned long long);
259 value = va_arg (args, ptrdiff_t);
260 #if UINTMAX_MAX != PTRDIFF_MAX
261 value &= ((uintmax_t) PTRDIFF_MAX << 1) | 1;
265 value = va_arg (args, size_t);
273 case 'o': b = &base_o; break;
274 case 'u': b = &base_d; break;
275 case 'x': b = &base_x; break;
276 case 'X': b = &base_X; break;
277 default: NOT_REACHED ();
280 format_integer (value, false, false, b, &c, output, aux);
286 /* Treat character as single-character string. */
287 char ch = va_arg (args, int);
288 format_string (&ch, 1, &c, output, aux);
294 /* String conversion. */
295 const char *s = va_arg (args, char *);
299 /* Limit string length according to precision.
300 Note: if c.precision == -1 then strnlen() will get
301 SIZE_MAX for MAXLEN, which is just what we want. */
302 format_string (s, strnlen (s, c.precision), &c, output, aux);
308 /* Pointer conversion.
309 Format pointers as %#x. */
310 void *p = va_arg (args, void *);
313 format_integer ((uintptr_t) p, false, false,
314 &base_x, &c, output, aux);
324 /* We don't support floating-point arithmetic,
325 and %n can be part of a security hole. */
326 __printf ("<<no %%%c in kernel>>", output, aux, *format);
330 __printf ("<<no %%%c conversion>>", output, aux, *format);
336 /* Parses conversion option characters starting at FORMAT and
337 initializes C appropriately. Returns the character in FORMAT
338 that indicates the conversion (e.g. the `d' in `%d'). Uses
339 *ARGS for `*' field widths and precisions. */
341 parse_conversion (const char *format, struct printf_conversion *c,
344 /* Parse flag characters. */
374 if (c->flags & MINUS)
379 /* Parse field width. */
384 c->width = va_arg (*args, int);
388 for (; isdigit (*format); format++)
389 c->width = c->width * 10 + *format - '0';
393 c->width = -c->width;
397 /* Parse precision. */
405 c->precision = va_arg (*args, int);
410 for (; isdigit (*format); format++)
411 c->precision = c->precision * 10 + *format - '0';
413 if (c->precision < 0)
416 if (c->precision >= 0)
463 /* Performs an integer conversion, writing output to OUTPUT with
464 auxiliary data AUX. The integer converted has absolute value
465 VALUE. If IS_SIGNED is true, does a signed conversion with
466 NEGATIVE indicating a negative value; otherwise does an
467 unsigned conversion and ignores IS_SIGNED. The output will
468 use the given DIGITS, with strlen(DIGITS) indicating the
469 output base. Details of the conversion are in C. */
471 format_integer (uintmax_t value, bool is_signed, bool negative,
472 const struct integer_base *b,
473 const struct printf_conversion *c,
474 void (*output) (char, void *), void *aux)
476 char buf[64], *cp; /* Buffer and current position. */
477 const char *signifier; /* b->signifier or "". */
478 int precision; /* Rendered precision. */
479 int pad_cnt; /* # of pad characters to fill field width. */
480 int digit_cnt; /* # of digits output so far. */
482 /* Accumulate digits into buffer.
483 This algorithm produces digits in reverse order, so later we
484 will output the buffer's content in reverse. This is also
485 the reason that later we append zeros and the sign. */
490 if ((c->flags & GROUP) && digit_cnt > 0 && digit_cnt % b->group == 0)
492 *cp++ = b->digits[value % b->base];
497 /* Append enough zeros to match precision.
498 If requested precision is 0, then a value of zero is
499 rendered as a null string, otherwise as "0". */
500 precision = c->precision < 0 ? 1 : c->precision;
501 while (cp - buf < precision && cp - buf < (int) sizeof buf - 8)
508 *cp++ = negative ? '-' : '+';
509 else if (c->flags & SPACE)
510 *cp++ = negative ? '-' : ' ';
515 /* Calculate number of pad characters to fill field width. */
516 signifier = c->flags & POUND ? b->signifier : "";
517 pad_cnt = c->width - (cp - buf) - strlen (signifier);
522 if ((c->flags & (MINUS | ZERO)) == 0)
523 output_dup (' ', pad_cnt, output, aux);
524 while (*signifier != '\0')
525 output (*signifier++, aux);
527 output_dup ('0', pad_cnt, output, aux);
530 if (c->flags & MINUS)
531 output_dup (' ', pad_cnt, output, aux);
534 /* Writes CH to OUTPUT with auxiliary data AUX, CNT times. */
536 output_dup (char ch, size_t cnt, void (*output) (char, void *), void *aux)
542 /* Formats the LENGTH characters starting at STRING according to
543 the conversion specified in C. Writes output to OUTPUT with
544 auxiliary data AUX. */
546 format_string (const char *string, int length,
547 struct printf_conversion *c,
548 void (*output) (char, void *), void *aux)
550 if (c->width > length && (c->flags & MINUS) == 0)
551 output_dup (' ', c->width - length, output, aux);
553 output (*string++, aux);
554 if (c->width > length && (c->flags & MINUS) != 0)
555 output_dup (' ', c->width - length, output, aux);
558 /* Wrapper for __vprintf() that converts varargs into a
561 __printf (const char *format,
562 void (*output) (char, void *), void *aux, ...)
566 va_start (args, aux);
567 __vprintf (format, args, output, aux);
571 /* Dumps the SIZE bytes in BUF to the console as hex bytes
572 arranged 16 per line. Numeric offsets are also included,
573 starting at OFS for the first byte in BUF. If ASCII is true
574 then the corresponding ASCII characters are also rendered
577 hex_dump (uintptr_t ofs, const void *buf_, size_t size, bool ascii)
579 const uint8_t *buf = buf_;
580 const size_t per_line = 16; /* Maximum bytes per line. */
584 size_t start, end, n;
587 /* Number of bytes on this line. */
588 start = ofs % per_line;
590 if (end - start > size)
595 printf ("%08jx ", (uintmax_t) ROUND_DOWN (ofs, per_line));
596 for (i = 0; i < start; i++)
600 buf[i - start], i == per_line / 2 - 1? '-' : ' ');
603 for (; i < per_line; i++)
606 for (i = 0; i < start; i++)
610 isprint (buf[i - start]) ? buf[i - start] : '.');
611 for (; i < per_line; i++)