CS318 - Pintos
Pintos source browser for JHU CS318 course
stdio.c
Go to the documentation of this file.
1 #include <stdio.h>
2 #include <ctype.h>
3 #include <inttypes.h>
4 #include <round.h>
5 #include <stdint.h>
6 #include <string.h>
7 
8 /** Auxiliary data for vsnprintf_helper(). */
9 struct vsnprintf_aux
10  {
11  char *p; /**< Current output position. */
12  int length; /**< Length of output string. */
13  int max_length; /**< Max length of output string. */
14  };
15 
16 static void vsnprintf_helper (char, void *);
17 
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. */
25 int
26 vsnprintf (char *buffer, size_t buf_size, const char *format, va_list args)
27 {
28  /* Set up aux data for vsnprintf_helper(). */
29  struct vsnprintf_aux aux;
30  aux.p = buffer;
31  aux.length = 0;
32  aux.max_length = buf_size > 0 ? buf_size - 1 : 0;
33 
34  /* Do most of the work. */
35  __vprintf (format, args, vsnprintf_helper, &aux);
36 
37  /* Add null terminator. */
38  if (buf_size > 0)
39  *aux.p = '\0';
40 
41  return aux.length;
42 }
43 
44 /** Helper function for vsnprintf(). */
45 static void
46 vsnprintf_helper (char ch, void *aux_)
47 {
48  struct vsnprintf_aux *aux = aux_;
49 
50  if (aux->length++ < aux->max_length)
51  *aux->p++ = ch;
52 }
53 
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. */
61 int
62 snprintf (char *buffer, size_t buf_size, const char *format, ...)
63 {
64  va_list args;
65  int retval;
66 
67  va_start (args, format);
68  retval = vsnprintf (buffer, buf_size, format, args);
69  va_end (args);
70 
71  return retval;
72 }
73 
74 /** Writes formatted output to the console.
75  In the kernel, the console is both the video display and first
76  serial port.
77  In userspace, the console is file descriptor 1. */
78 int
79 printf (const char *format, ...)
80 {
81  va_list args;
82  int retval;
83 
84  va_start (args, format);
85  retval = vprintf (format, args);
86  va_end (args);
87 
88  return retval;
89 }
90 
91 /** printf() formatting internals. */
92 
93 /** A printf() conversion. */
95  {
96  /* Flags. */
97  enum
98  {
99  MINUS = 1 << 0, /**< '-' */
100  PLUS = 1 << 1, /**< '+' */
101  SPACE = 1 << 2, /**< ' ' */
102  POUND = 1 << 3, /**< '#' */
103  ZERO = 1 << 4, /**< '0' */
104  GROUP = 1 << 5 /**< '\'' */
105  }
106  flags;
107 
108  /* Minimum field width. */
109  int width;
110 
111  /* Numeric precision.
112  -1 indicates no precision was specified. */
114 
115  /* Type of argument to format. */
116  enum
117  {
118  CHAR = 1, /**< hh */
119  SHORT = 2, /**< h */
120  INT = 3, /**< (none) */
121  INTMAX = 4, /**< j */
122  LONG = 5, /**< l */
123  LONGLONG = 6, /**< ll */
124  PTRDIFFT = 7, /**< t */
125  SIZET = 8 /**< z */
126  }
127  type;
128  };
129 
131  {
132  int base; /**< Base. */
133  const char *digits; /**< Collection of digits. */
134  int x; /**< `x' character to use, for base 16 only. */
135  int group; /**< Number of digits to group with ' flag. */
136  };
137 
138 static const struct integer_base base_d = {10, "0123456789", 0, 3};
139 static const struct integer_base base_o = {8, "01234567", 0, 3};
140 static const struct integer_base base_x = {16, "0123456789abcdef", 'x', 4};
141 static const struct integer_base base_X = {16, "0123456789ABCDEF", 'X', 4};
142 
143 static const char *parse_conversion (const char *format,
144  struct printf_conversion *,
145  va_list *);
146 static void format_integer (uintmax_t value, bool is_signed, bool negative,
147  const struct integer_base *,
148  const struct printf_conversion *,
149  void (*output) (char, void *), void *aux);
150 static void output_dup (char ch, size_t cnt,
151  void (*output) (char, void *), void *aux);
152 static void format_string (const char *string, int length,
153  struct printf_conversion *,
154  void (*output) (char, void *), void *aux);
155 
156 void
157 __vprintf (const char *format, va_list args,
158  void (*output) (char, void *), void *aux)
159 {
160  for (; *format != '\0'; format++)
161  {
162  struct printf_conversion c;
163 
164  /* Literally copy non-conversions to output. */
165  if (*format != '%')
166  {
167  output (*format, aux);
168  continue;
169  }
170  format++;
171 
172  /* %% => %. */
173  if (*format == '%')
174  {
175  output ('%', aux);
176  continue;
177  }
178 
179  /* Parse conversion specifiers. */
180  format = parse_conversion (format, &c, &args);
181 
182  /* Do conversion. */
183  switch (*format)
184  {
185  case 'd':
186  case 'i':
187  {
188  /* Signed integer conversions. */
189  intmax_t value;
190 
191  switch (c.type)
192  {
193  case CHAR:
194  value = (signed char) va_arg (args, int);
195  break;
196  case SHORT:
197  value = (short) va_arg (args, int);
198  break;
199  case INT:
200  value = va_arg (args, int);
201  break;
202  case INTMAX:
203  value = va_arg (args, intmax_t);
204  break;
205  case LONG:
206  value = va_arg (args, long);
207  break;
208  case LONGLONG:
209  value = va_arg (args, long long);
210  break;
211  case PTRDIFFT:
212  value = va_arg (args, ptrdiff_t);
213  break;
214  case SIZET:
215  value = va_arg (args, size_t);
216  if (value > SIZE_MAX / 2)
217  value = value - SIZE_MAX - 1;
218  break;
219  default:
220  NOT_REACHED ();
221  }
222 
223  format_integer (value < 0 ? -value : value,
224  true, value < 0, &base_d, &c, output, aux);
225  }
226  break;
227 
228  case 'o':
229  case 'u':
230  case 'x':
231  case 'X':
232  {
233  /* Unsigned integer conversions. */
235  const struct integer_base *b;
236 
237  switch (c.type)
238  {
239  case CHAR:
240  value = (unsigned char) va_arg (args, unsigned);
241  break;
242  case SHORT:
243  value = (unsigned short) va_arg (args, unsigned);
244  break;
245  case INT:
246  value = va_arg (args, unsigned);
247  break;
248  case INTMAX:
249  value = va_arg (args, uintmax_t);
250  break;
251  case LONG:
252  value = va_arg (args, unsigned long);
253  break;
254  case LONGLONG:
255  value = va_arg (args, unsigned long long);
256  break;
257  case PTRDIFFT:
258  value = va_arg (args, ptrdiff_t);
259 #if UINTMAX_MAX != PTRDIFF_MAX
260  value &= ((uintmax_t) PTRDIFF_MAX << 1) | 1;
261 #endif
262  break;
263  case SIZET:
264  value = va_arg (args, size_t);
265  break;
266  default:
267  NOT_REACHED ();
268  }
269 
270  switch (*format)
271  {
272  case 'o': b = &base_o; break;
273  case 'u': b = &base_d; break;
274  case 'x': b = &base_x; break;
275  case 'X': b = &base_X; break;
276  default: NOT_REACHED ();
277  }
278 
279  format_integer (value, false, false, b, &c, output, aux);
280  }
281  break;
282 
283  case 'c':
284  {
285  /* Treat character as single-character string. */
286  char ch = va_arg (args, int);
287  format_string (&ch, 1, &c, output, aux);
288  }
289  break;
290 
291  case 's':
292  {
293  /* String conversion. */
294  const char *s = va_arg (args, char *);
295  if (s == NULL)
296  s = "(null)";
297 
298  /* Limit string length according to precision.
299  Note: if c.precision == -1 then strnlen() will get
300  SIZE_MAX for MAXLEN, which is just what we want. */
301  format_string (s, strnlen (s, c.precision), &c, output, aux);
302  }
303  break;
304 
305  case 'p':
306  {
307  /* Pointer conversion.
308  Format pointers as %#x. */
309  void *p = va_arg (args, void *);
310 
311  c.flags = POUND;
312  format_integer ((uintptr_t) p, false, false,
313  &base_x, &c, output, aux);
314  }
315  break;
316 
317  case 'f':
318  case 'e':
319  case 'E':
320  case 'g':
321  case 'G':
322  case 'n':
323  /* We don't support floating-point arithmetic,
324  and %n can be part of a security hole. */
325  __printf ("<<no %%%c in kernel>>", output, aux, *format);
326  break;
327 
328  default:
329  __printf ("<<no %%%c conversion>>", output, aux, *format);
330  break;
331  }
332  }
333 }
334 
335 /** Parses conversion option characters starting at FORMAT and
336  initializes C appropriately. Returns the character in FORMAT
337  that indicates the conversion (e.g. the `d' in `%d'). Uses
338  *ARGS for `*' field widths and precisions. */
339 static const char *
340 parse_conversion (const char *format, struct printf_conversion *c,
341  va_list *args)
342 {
343  /* Parse flag characters. */
344  c->flags = 0;
345  for (;;)
346  {
347  switch (*format++)
348  {
349  case '-':
350  c->flags |= MINUS;
351  break;
352  case '+':
353  c->flags |= PLUS;
354  break;
355  case ' ':
356  c->flags |= SPACE;
357  break;
358  case '#':
359  c->flags |= POUND;
360  break;
361  case '0':
362  c->flags |= ZERO;
363  break;
364  case '\'':
365  c->flags |= GROUP;
366  break;
367  default:
368  format--;
369  goto not_a_flag;
370  }
371  }
372  not_a_flag:
373  if (c->flags & MINUS)
374  c->flags &= ~ZERO;
375  if (c->flags & PLUS)
376  c->flags &= ~SPACE;
377 
378  /* Parse field width. */
379  c->width = 0;
380  if (*format == '*')
381  {
382  format++;
383  c->width = va_arg (*args, int);
384  }
385  else
386  {
387  for (; isdigit (*format); format++)
388  c->width = c->width * 10 + *format - '0';
389  }
390  if (c->width < 0)
391  {
392  c->width = -c->width;
393  c->flags |= MINUS;
394  }
395 
396  /* Parse precision. */
397  c->precision = -1;
398  if (*format == '.')
399  {
400  format++;
401  if (*format == '*')
402  {
403  format++;
404  c->precision = va_arg (*args, int);
405  }
406  else
407  {
408  c->precision = 0;
409  for (; isdigit (*format); format++)
410  c->precision = c->precision * 10 + *format - '0';
411  }
412  if (c->precision < 0)
413  c->precision = -1;
414  }
415  if (c->precision >= 0)
416  c->flags &= ~ZERO;
417 
418  /* Parse type. */
419  c->type = INT;
420  switch (*format++)
421  {
422  case 'h':
423  if (*format == 'h')
424  {
425  format++;
426  c->type = CHAR;
427  }
428  else
429  c->type = SHORT;
430  break;
431 
432  case 'j':
433  c->type = INTMAX;
434  break;
435 
436  case 'l':
437  if (*format == 'l')
438  {
439  format++;
440  c->type = LONGLONG;
441  }
442  else
443  c->type = LONG;
444  break;
445 
446  case 't':
447  c->type = PTRDIFFT;
448  break;
449 
450  case 'z':
451  c->type = SIZET;
452  break;
453 
454  default:
455  format--;
456  break;
457  }
458 
459  return format;
460 }
461 
462 /** Performs an integer conversion, writing output to OUTPUT with
463  auxiliary data AUX. The integer converted has absolute value
464  VALUE. If IS_SIGNED is true, does a signed conversion with
465  NEGATIVE indicating a negative value; otherwise does an
466  unsigned conversion and ignores NEGATIVE. The output is done
467  according to the provided base B. Details of the conversion
468  are in C. */
469 static void
470 format_integer (uintmax_t value, bool is_signed, bool negative,
471  const struct integer_base *b,
472  const struct printf_conversion *c,
473  void (*output) (char, void *), void *aux)
474 {
475  char buf[64], *cp; /**< Buffer and current position. */
476  int x; /**< `x' character to use or 0 if none. */
477  int sign; /**< Sign character or 0 if none. */
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. */
481 
482  /* Determine sign character, if any.
483  An unsigned conversion will never have a sign character,
484  even if one of the flags requests one. */
485  sign = 0;
486  if (is_signed)
487  {
488  if (c->flags & PLUS)
489  sign = negative ? '-' : '+';
490  else if (c->flags & SPACE)
491  sign = negative ? '-' : ' ';
492  else if (negative)
493  sign = '-';
494  }
495 
496  /* Determine whether to include `0x' or `0X'.
497  It will only be included with a hexadecimal conversion of a
498  nonzero value with the # flag. */
499  x = (c->flags & POUND) && value ? b->x : 0;
500 
501  /* Accumulate digits into buffer.
502  This algorithm produces digits in reverse order, so later we
503  will output the buffer's content in reverse. */
504  cp = buf;
505  digit_cnt = 0;
506  while (value > 0)
507  {
508  if ((c->flags & GROUP) && digit_cnt > 0 && digit_cnt % b->group == 0)
509  *cp++ = ',';
510  *cp++ = b->digits[value % b->base];
511  value /= b->base;
512  digit_cnt++;
513  }
514 
515  /* Append enough zeros to match precision.
516  If requested precision is 0, then a value of zero is
517  rendered as a null string, otherwise as "0".
518  If the # flag is used with base 8, the result must always
519  begin with a zero. */
520  precision = c->precision < 0 ? 1 : c->precision;
521  while (cp - buf < precision && cp < buf + sizeof buf - 1)
522  *cp++ = '0';
523  if ((c->flags & POUND) && b->base == 8 && (cp == buf || cp[-1] != '0'))
524  *cp++ = '0';
525 
526  /* Calculate number of pad characters to fill field width. */
527  pad_cnt = c->width - (cp - buf) - (x ? 2 : 0) - (sign != 0);
528  if (pad_cnt < 0)
529  pad_cnt = 0;
530 
531  /* Do output. */
532  if ((c->flags & (MINUS | ZERO)) == 0)
533  output_dup (' ', pad_cnt, output, aux);
534  if (sign)
535  output (sign, aux);
536  if (x)
537  {
538  output ('0', aux);
539  output (x, aux);
540  }
541  if (c->flags & ZERO)
542  output_dup ('0', pad_cnt, output, aux);
543  while (cp > buf)
544  output (*--cp, aux);
545  if (c->flags & MINUS)
546  output_dup (' ', pad_cnt, output, aux);
547 }
548 
549 /** Writes CH to OUTPUT with auxiliary data AUX, CNT times. */
550 static void
551 output_dup (char ch, size_t cnt, void (*output) (char, void *), void *aux)
552 {
553  while (cnt-- > 0)
554  output (ch, aux);
555 }
556 
557 /** Formats the LENGTH characters starting at STRING according to
558  the conversion specified in C. Writes output to OUTPUT with
559  auxiliary data AUX. */
560 static void
561 format_string (const char *string, int length,
562  struct printf_conversion *c,
563  void (*output) (char, void *), void *aux)
564 {
565  int i;
566  if (c->width > length && (c->flags & MINUS) == 0)
567  output_dup (' ', c->width - length, output, aux);
568  for (i = 0; i < length; i++)
569  output (string[i], aux);
570  if (c->width > length && (c->flags & MINUS) != 0)
571  output_dup (' ', c->width - length, output, aux);
572 }
573 
574 /** Wrapper for __vprintf() that converts varargs into a
575  va_list. */
576 void
577 __printf (const char *format,
578  void (*output) (char, void *), void *aux, ...)
579 {
580  va_list args;
581 
582  va_start (args, aux);
583  __vprintf (format, args, output, aux);
584  va_end (args);
585 }
586 
587 /** Dumps the SIZE bytes in BUF to the console as hex bytes
588  arranged 16 per line. Numeric offsets are also included,
589  starting at OFS for the first byte in BUF. If ASCII is true
590  then the corresponding ASCII characters are also rendered
591  alongside. */
592 void
593 hex_dump (uintptr_t ofs, const void *buf_, size_t size, bool ascii)
594 {
595  const uint8_t *buf = buf_;
596  const size_t per_line = 16; /**< Maximum bytes per line. */
597 
598  while (size > 0)
599  {
600  size_t start, end, n;
601  size_t i;
602 
603  /* Number of bytes on this line. */
604  start = ofs % per_line;
605  end = per_line;
606  if (end - start > size)
607  end = start + size;
608  n = end - start;
609 
610  /* Print line. */
611  printf ("%08jx ", (uintmax_t) ROUND_DOWN (ofs, per_line));
612  for (i = 0; i < start; i++)
613  printf (" ");
614  for (; i < end; i++)
615  printf ("%02hhx%c",
616  buf[i - start], i == per_line / 2 - 1? '-' : ' ');
617  if (ascii)
618  {
619  for (; i < per_line; i++)
620  printf (" ");
621  printf ("|");
622  for (i = 0; i < start; i++)
623  printf (" ");
624  for (; i < end; i++)
625  printf ("%c",
626  isprint (buf[i - start]) ? buf[i - start] : '.');
627  for (; i < per_line; i++)
628  printf (" ");
629  printf ("|");
630  }
631  printf ("\n");
632 
633  ofs += n;
634  buf += n;
635  size -= n;
636  }
637 }
638 
639 /** Prints SIZE, which represents a number of bytes, in a
640  human-readable format, e.g. "256 kB". */
641 void
643 {
644  if (size == 1)
645  printf ("1 byte");
646  else
647  {
648  static const char *factors[] = {"bytes", "kB", "MB", "GB", "TB", NULL};
649  const char **fp;
650 
651  for (fp = factors; size >= 1024 && fp[1] != NULL; fp++)
652  size /= 1024;
653  printf ("%"PRIu64" %s", size, *fp);
654  }
655 }
uint64_t
unsigned long long int uint64_t
Definition: stdint.h:29
snprintf
int snprintf(char *buffer, size_t buf_size, const char *format,...)
Like printf(), except that output is stored into BUFFER, which must have space for BUF_SIZE character...
Definition: stdio.c:62
start
char * start[]
Insult.c.
Definition: insult.c:13
base_o
static const struct integer_base base_o
Definition: stdio.c:139
uint8_t
unsigned char uint8_t
Definition: stdint.h:20
integer_base::base
int base
Base.
Definition: stdio.c:132
isprint
static int isprint(int c)
Definition: ctype.h:18
va_end
#define va_end(LIST)
Definition: stdarg.h:10
__printf
void __printf(const char *format, void(*output)(char, void *), void *aux,...)
Wrapper for __vprintf() that converts varargs into a va_list.
Definition: stdio.c:577
format_integer
static void format_integer(uintmax_t value, bool is_signed, bool negative, const struct integer_base *, const struct printf_conversion *, void(*output)(char, void *), void *aux)
Performs an integer conversion, writing output to OUTPUT with auxiliary data AUX.
Definition: stdio.c:470
va_start
#define va_start(LIST, ARG)
Definition: stdarg.h:9
NULL
#define NULL
Definition: stddef.h:4
string.h
buf
static char buf[BUF_SIZE]
Definition: child-syn-read.c:16
printf_conversion::CHAR
hh
Definition: stdio.c:118
printf_conversion::PTRDIFFT
t
Definition: stdio.c:124
printf_conversion::LONGLONG
ll
Definition: stdio.c:123
printf_conversion::INTMAX
j
Definition: stdio.c:121
ptrdiff_t
__PTRDIFF_TYPE__ ptrdiff_t
GCC predefines the types we need for ptrdiff_t and size_t, so that we don't have to guess.
Definition: stddef.h:9
printf_conversion::SIZET
z
Definition: stdio.c:125
printf_conversion::precision
int precision
Definition: stdio.c:113
printf_conversion
printf() formatting internals.
Definition: stdio.c:94
printf_conversion::width
int width
Definition: stdio.c:109
NOT_REACHED
#define NOT_REACHED()
lib/debug.h
Definition: debug.h:35
integer_base
Definition: stdio.c:130
printf_conversion::GROUP
'\''
Definition: stdio.c:104
hex_dump
void hex_dump(uintptr_t ofs, const void *buf_, size_t size, bool ascii)
Dumps the SIZE bytes in BUF to the console as hex bytes arranged 16 per line.
Definition: stdio.c:593
ctype.h
buffer
static struct intq buffer
Stores keys from the keyboard and serial port.
Definition: input.c:7
printf
int printf(const char *format,...)
Writes formatted output to the console.
Definition: stdio.c:79
printf_conversion::SPACE
' '
Definition: stdio.c:101
__vprintf
void __vprintf(const char *format, va_list args, void(*output)(char, void *), void *aux)
Internal functions.
Definition: stdio.c:157
vsnprintf_aux
Auxiliary data for vsnprintf_helper().
Definition: stdio.c:9
SIZE_MAX
#define SIZE_MAX
lib/stdint.h
Definition: stdint.h:49
vsnprintf_aux::max_length
int max_length
Max length of output string.
Definition: stdio.c:13
printf_conversion::flags
enum printf_conversion::@1 flags
vprintf
int vprintf(const char *format, va_list args)
The standard vprintf() function, which is like printf() but uses a va_list.
Definition: console.c:126
va_arg
#define va_arg(LIST, TYPE)
Definition: stdarg.h:11
printf_conversion::SHORT
h
Definition: stdio.c:119
stdio.h
printf_conversion::LONG
l
Definition: stdio.c:122
round.h
stdint.h
va_list
__builtin_va_list va_list
GCC has <stdarg.h> functionality as built-ins, so all we need is to use it.
Definition: stdarg.h:7
x
static char x
Verifies that mapping over the data segment is disallowed.
Definition: mmap-over-data.c:9
printf_conversion::INT
(none)
Definition: stdio.c:120
printf_conversion::type
enum printf_conversion::@2 type
strnlen
size_t strnlen(const char *string, size_t maxlen)
If STRING is less than MAXLEN characters in length, returns its actual length.
Definition: string.c:307
format_string
static void format_string(const char *string, int length, struct printf_conversion *, void(*output)(char, void *), void *aux)
Formats the LENGTH characters starting at STRING according to the conversion specified in C.
Definition: stdio.c:561
value
A linked list element.
Definition: list.c:22
vsnprintf_aux::p
char * p
Current output position.
Definition: stdio.c:11
printf_conversion::PLUS
'+'
Definition: stdio.c:100
printf_conversion::ZERO
'0'
Definition: stdio.c:103
vsnprintf
int vsnprintf(char *buffer, size_t buf_size, const char *format, va_list args)
Like vprintf(), except that output is stored into BUFFER, which must have space for BUF_SIZE characte...
Definition: stdio.c:26
s
static uint8_t s[256]
RC4-based pseudo-random number generator (PRNG).
Definition: random.c:17
base_d
static const struct integer_base base_d
Definition: stdio.c:138
vsnprintf_helper
static void vsnprintf_helper(char, void *)
Helper function for vsnprintf().
Definition: stdio.c:46
intmax_t
int64_t intmax_t
Definition: stdint.h:39
PRIu64
#define PRIu64
Definition: inttypes.h:30
integer_base::digits
const char * digits
Collection of digits.
Definition: stdio.c:133
base_X
static const struct integer_base base_X
Definition: stdio.c:141
print_human_readable_size
void print_human_readable_size(uint64_t size)
Prints SIZE, which represents a number of bytes, in a human-readable format, e.g.
Definition: stdio.c:642
output_dup
static void output_dup(char ch, size_t cnt, void(*output)(char, void *), void *aux)
Writes CH to OUTPUT with auxiliary data AUX, CNT times.
Definition: stdio.c:551
ROUND_DOWN
#define ROUND_DOWN(X, STEP)
Yields X rounded down to the nearest multiple of STEP.
Definition: round.h:14
printf_conversion::POUND
'#'
Definition: stdio.c:102
vsnprintf_aux::length
int length
Length of output string.
Definition: stdio.c:12
parse_conversion
static const char * parse_conversion(const char *format, struct printf_conversion *, va_list *)
Parses conversion option characters starting at FORMAT and initializes C appropriately.
Definition: stdio.c:340
uintptr_t
uint32_t uintptr_t
Definition: stdint.h:36
integer_base::group
int group
Number of digits to group with ' flag.
Definition: stdio.c:135
base_x
static const struct integer_base base_x
Definition: stdio.c:140
integer_base::x
int x
‘x’ character to use, for base 16 only.
Definition: stdio.c:134
uintmax_t
uint64_t uintmax_t
Definition: stdint.h:43
isdigit
static int isdigit(int c)
Definition: ctype.h:7
inttypes.h
printf_conversion::MINUS
'-'
Definition: stdio.c:99
PTRDIFF_MAX
#define PTRDIFF_MAX
Definition: stdint.h:47