8fe516194ff0b89cef848b4eb0b551f4be005f2d
[pintos-anon] / src / lib / lib.c
1 #include <stdint.h>
2 #include <stdarg.h>
3 #include <stdbool.h>
4 #include <stddef.h>
5 #include "debug.h"
6 #include "interrupt.h"
7 #include "lib.h"
8 #include "serial.h"
9 #include "vga.h"
10
11 static void
12 vprintf_core (const char *format, va_list args,
13               void (*output) (char, void *), void *aux);
14 \f
15 /* <string.h> */
16
17 /* Sets the SIZE bytes in DST to VALUE. */
18 void *
19 memset (void *dst_, int value, size_t size) 
20 {
21   unsigned char *dst = dst_;
22
23   ASSERT (dst != NULL || size == 0);
24   
25   while (size-- > 0)
26     *dst++ = value;
27
28   return dst_;
29 }
30
31 /* Copies SIZE bytes from SRC to DST, which must not overlap.
32    Returns DST. */
33 void *
34 memcpy (void *dst_, const void *src_, size_t size) 
35 {
36   unsigned char *dst = dst_;
37   const unsigned char *src = src_;
38
39   ASSERT (dst != NULL || size == 0);
40   ASSERT (src != NULL || size == 0);
41
42   while (size-- > 0)
43     *dst++ = *src++;
44
45   return dst_;
46 }
47
48 /* Copies SIZE bytes from SRC to DST, which are allowed to
49    overlap.  Returns DST. */
50 void *
51 memmove (void *dst_, const void *src_, size_t size) 
52 {
53   unsigned char *dst = dst_;
54   const unsigned char *src = src_;
55
56   ASSERT (dst != NULL || size == 0);
57   ASSERT (src != NULL || size == 0);
58
59   if (dst < src) 
60     {
61       while (size-- > 0)
62         *dst++ = *src++;
63     }
64   else 
65     {
66       dst += size;
67       src += size;
68       while (size-- > 0)
69         *--dst = *--src;
70     }
71
72   return dst;
73 }
74
75 /* Returns a pointer to the first occurrence of CH in the first
76    SIZE bytes starting at BLOCK.  Returns a null pointer if CH
77    does not occur in BLOCK. */
78 void *
79 memchr (const void *block_, int ch_, size_t size) 
80 {
81   const unsigned char *block = block_;
82   unsigned char ch = ch_;
83
84   ASSERT (block != NULL || size == 0);
85
86   for (; size-- > 0; block++)
87     if (*block == ch)
88       return (void *) block;
89
90   return NULL;
91 }
92
93 /* Find the first differing byte in the two blocks of SIZE bytes
94    at A and B.  Returns a positive value if the byte in A is
95    greater, a negative value if the byte in B is greater, or zero
96    if blocks A and B are equal. */
97 int
98 memcmp (const void *a_, const void *b_, size_t size) 
99 {
100   const unsigned char *a = a_;
101   const unsigned char *b = b_;
102
103   ASSERT (a != NULL || size == 0);
104   ASSERT (b != NULL || size == 0);
105
106   for (; size-- > 0; a++, b++)
107     if (*a != *b)
108       return *a > *b ? +1 : -1;
109   return 0;
110 }
111
112 /* Finds and returns the first occurrence of C in STRING, or a
113    null pointer if C does not appear in STRING.  If C == '\0'
114    then returns a pointer to the null terminator at the end of
115    STRING. */
116 char *
117 strchr (const char *string, int c_) 
118 {
119   char c = c_;
120
121   ASSERT (string != NULL);
122
123   for (;;) 
124     if (*string == c)
125       return (char *) string;
126     else if (*string == '\0')
127       return NULL;
128     else
129       string++;
130 }
131
132 /* Copies string SRC to DST.  If SRC is longer than SIZE - 1
133    characters, only SIZE - 1 characters are copied.  A null
134    terminator is always written to DST, unless SIZE is 0.
135    Returns the length of SRC.
136
137    strlcpy() is not in the standard C library, but it is an
138    increasingly popular extension.  See
139    http://www.courtesan.com/todd/papers/strlcpy.html for
140    information on strlcpy(). */
141 size_t
142 strlcpy (char *dst, const char *src, size_t size) 
143 {
144   size_t src_len;
145
146   ASSERT (dst != NULL);
147   ASSERT (src != NULL);
148
149   src_len = strlen (src);
150   if (size > 0) 
151     {
152       size_t dst_len = size - 1;
153       if (src_len < dst_len)
154         src_len = dst_len;
155       memcpy (dst, src, dst_len);
156       dst[dst_len] = '\0';
157     }
158   return src_len;
159 }
160
161 /* Returns the length of STRING. */
162 size_t
163 strlen (const char *string) 
164 {
165   const char *p;
166
167   ASSERT (string != NULL);
168
169   for (p = string; *p != '\0'; p++)
170     continue;
171   return p - string;
172 }
173
174 /* If STRING is less than MAXLEN characters in length, returns
175    its actual length.  Otherwise, returns MAXLEN. */
176 size_t
177 strnlen (const char *string, size_t maxlen) 
178 {
179   size_t length;
180
181   for (length = 0; string[length] != '\0' && length < maxlen; length++)
182     continue;
183   return length;
184 }
185
186 /* Finds the first differing characters in strings A and B.
187    Returns a positive value if the character in A (as an unsigned
188    char) is greater, a negative value if the character in B (as
189    an unsigned char) is greater, or zero if strings A and B are
190    equal. */
191 int
192 strcmp (const char *a_, const char *b_) 
193 {
194   const unsigned char *a = (const unsigned char *) a_;
195   const unsigned char *b = (const unsigned char *) b_;
196
197   ASSERT (a != NULL);
198   ASSERT (b != NULL);
199
200   while (*a != '\0' && *a == *b) 
201     {
202       a++;
203       b++;
204     }
205
206   return *a < *b ? -1 : *a > *b;
207 }
208
209 /* Breaks a string into tokens separated by DELIMITERS.  The
210    first time this function is called, S should be the string to
211    tokenize, and in subsequent calls it must be a null pointer.
212    SAVE_PTR is the address of a `char *' variable used to keep
213    track of the tokenizer's position.  The return value each time
214    is the next token in the string, or a null pointer if no
215    tokens remain.
216
217    This function treats multiple adjacent delimiters as a single
218    delimiter.  The returned tokens will never be length 0.
219    DELIMITERS may change from one call to the next within a
220    single string.
221
222    strtok_r() modifies the string S, changing delimiters to null
223    bytes.  Thus, S must be a modifiable string.
224
225    Example usage:
226
227    char s[] = "  String to  tokenize. ";
228    char *token, *save_ptr;
229
230    for (token = strtok_r (s, " ", &save_ptr); token != NULL;
231         token = strtok_r (NULL, " ", &save_ptr))
232      printf ("'%s'\n", token);
233
234    outputs:
235
236      'String'
237      'to'
238      'tokenize.'
239 */
240 char *
241 strtok_r (char *s, const char *delimiters, char **save_ptr) 
242 {
243   char *token;
244   
245   ASSERT (delimiters != NULL);
246   ASSERT (save_ptr != NULL);
247
248   /* If S is nonnull, start from it.
249      If S is null, start from saved position. */
250   if (s == NULL)
251     s = *save_ptr;
252   ASSERT (s != NULL);
253
254   /* Skip any DELIMITERS at our current position. */
255   while (strchr (delimiters, *s) != NULL) 
256     {
257       /* strchr() will always return nonnull if we're searching
258          for a null byte, because every string contains a null
259          byte (at the end). */
260       if (*s == '\0')
261         {
262           *save_ptr = s;
263           return NULL;
264         }
265
266       s++;
267     }
268
269   /* Skip any non-DELIMITERS up to the end of the string. */
270   token = s;
271   while (strchr (delimiters, *s) == NULL)
272     s++;
273   if (*s != '\0') 
274     {
275       *s = '\0';
276       *save_ptr = s + 1;
277     }
278   else 
279     *save_ptr = s;
280   return token;
281 }
282 \f
283 /* <stdlib.h> */
284
285 /* Converts a string representation of a signed decimal integer
286    in S into an `int', which is returned. */
287 int
288 atoi (const char *s) 
289 {
290   bool negative;
291   int value;
292
293   /* Skip white space. */
294   while (isspace (*s))
295     s++;
296
297   /* Parse sign. */
298   negative = false;
299   if (*s == '+')
300     s++;
301   else if (*s == '-')
302     {
303       negative = true;
304       s++;
305     }
306
307   /* Parse digits.  We always initially parse the value as
308      negative, and then make it positive later, because the
309      negative range of an int is bigger than the positive range
310      on a 2's complement system. */
311   for (value = 0; isdigit (*s); s++)
312     value = value * 10 - (*s - '0');
313   if (!negative)
314     value = -value;
315
316   return value;
317 }
318 \f
319 /* <stdio.h> */
320
321 /* Auxiliary data for vsnprintf_helper(). */
322 struct vsnprintf_aux 
323   {
324     char *p;            /* Current output position. */
325     int length;         /* Length of output string. */
326     int max_length;     /* Max length of output string. */
327   };
328
329 static void vsnprintf_helper (char, void *);
330
331 /* Like vprintf(), except that output is stored into BUFFER,
332    which must have space for BUF_SIZE characters.  Writes at most
333    BUF_SIZE - 1 characters to BUFFER, followed by a null
334    terminator.  BUFFER will always be null-terminated unless
335    BUF_SIZE is zero.  Returns the number of characters that would
336    have been written to BUFFER, not including a null terminator,
337    had there been enough room. */
338 int
339 vsnprintf (char *buffer, size_t buf_size, const char *format, va_list args) 
340 {
341   /* Set up aux data for vsnprintf_helper(). */
342   struct vsnprintf_aux aux;
343   aux.p = buffer;
344   aux.length = 0;
345   aux.max_length = buf_size > 0 ? buf_size - 1 : 0;
346
347   /* Do most of the work. */
348   vprintf_core (format, args, vsnprintf_helper, &aux);
349
350   /* Add null terminator. */
351   if (buf_size > 0)
352     *aux.p = '\0';
353
354   return aux.length;
355 }
356
357 /* Helper function for vsnprintf(). */
358 static void
359 vsnprintf_helper (char ch, void *aux_)
360 {
361   struct vsnprintf_aux *aux = aux_;
362
363   if (aux->length++ < aux->max_length)
364     *aux->p++ = ch;
365 }
366
367 /* Like printf(), except that output is stored into BUFFER,
368    which must have space for BUF_SIZE characters.  Writes at most
369    BUF_SIZE - 1 characters to BUFFER, followed by a null
370    terminator.  BUFFER will always be null-terminated unless
371    BUF_SIZE is zero.  Returns the number of characters that would
372    have been written to BUFFER, not including a null terminator,
373    had there been enough room. */
374 int
375 snprintf (char *buffer, size_t buf_size, const char *format, ...) 
376 {
377   va_list args;
378   int retval;
379
380   va_start (args, format);
381   retval = vsnprintf (buffer, buf_size, format, args);
382   va_end (args);
383
384   return retval;
385 }
386 \f
387 /* Nonstandard functions. */
388
389 static void vprintk_helper (char, void *);
390
391 /* Like vprintf(), except that output is written to the system
392    console, which is defined as the video display and the first
393    serial port (at the same time). */
394 void
395 vprintk (const char *format, va_list args) 
396 {
397   enum intr_level old_level = intr_disable ();
398   vprintf_core (format, args, vprintk_helper, NULL);
399   intr_set_level (old_level);
400 }
401
402 /* Helper function for vprintk(). */
403 static void
404 vprintk_helper (char ch, void *aux UNUSED) 
405 {
406   vga_putc (ch);
407   serial_outb (ch);
408 }
409
410 /* Like printf(), except that output is written to the system
411    console, which is defined as the video display and the first
412    serial port (at the same time). */
413 void
414 printk (const char *format, ...) 
415 {
416   va_list args;
417
418   va_start (args, format);
419   vprintk (format, args);
420   va_end (args);
421 }
422 \f
423 /* printf() formatting internals. */
424
425 /* A printf() conversion. */
426 struct printf_conversion 
427   {
428     /* Flags. */
429     enum 
430       {
431         MINUS = 1 << 0,         /* '-' */
432         PLUS = 1 << 1,          /* '+' */
433         SPACE = 1 << 2,         /* ' ' */
434         POUND = 1 << 3,         /* '#' */
435         ZERO = 1 << 4,          /* '0' */
436         GROUP = 1 << 5          /* '\'' */
437       }
438     flags;
439
440     /* Minimum field width. */
441     int width;
442
443     /* Numeric precision.
444        -1 indicates no precision was specified. */
445     int precision;
446
447     /* Type of argument to format. */
448     enum 
449       {
450         CHAR = 1,               /* hh */
451         SHORT = 2,              /* h */
452         INT = 3,                /* (none) */
453         INTMAX = 4,             /* j */
454         LONG = 5,               /* l */
455         LONGLONG = 6,           /* ll */
456         PTRDIFFT = 7,           /* t */
457         SIZET = 8               /* z */
458       }
459     type;
460   };
461
462 struct integer_base 
463   {
464     int base;                   /* Base. */
465     const char *digits;         /* Collection of digits. */
466     const char *signifier;      /* Prefix used with # flag. */
467     int group;                  /* Number of digits to group with ' flag. */
468   };
469
470 static const struct integer_base base_d = {10, "0123456789", "", 3};
471 static const struct integer_base base_o = {8, "01234567", "0", 3};
472 static const struct integer_base base_x = {16, "0123456789abcdef", "0x", 4};
473 static const struct integer_base base_X = {16, "0123456789ABCDEF", "0X", 4};
474
475 static const char *parse_conversion (const char *format,
476                                      struct printf_conversion *,
477                                      va_list *);
478 static void format_integer (uintmax_t value, bool negative,
479                             const struct integer_base *,
480                             const struct printf_conversion *,
481                             void (*output) (char, void *), void *aux);
482 static void output_dup (char ch, size_t cnt,
483                         void (*output) (char, void *), void *aux);
484 static void format_string (const char *string, size_t length,
485                            struct printf_conversion *,
486                            void (*output) (char, void *), void *aux);
487 static void printf_core (const char *format,
488                          void (*output) (char, void *), void *aux, ...);
489
490 static void
491 vprintf_core (const char *format, va_list args,
492               void (*output) (char, void *), void *aux)
493 {
494   for (; *format != '\0'; format++)
495     {
496       struct printf_conversion c;
497
498       /* Literally copy non-conversions to output. */
499       if (*format != '%') 
500         {
501           output (*format, aux);
502           continue;
503         }
504       format++;
505
506       /* %% => %. */
507       if (*format == '%') 
508         {
509           output ('%', aux);
510           continue;
511         }
512
513       /* Parse conversion specifiers. */
514       format = parse_conversion (format, &c, &args);
515
516       /* Do conversion. */
517       switch (*format) 
518         {
519         case 'd':
520         case 'i': 
521           {
522             /* Signed integer conversions. */
523             intmax_t value;
524             
525             switch (c.type) 
526               {
527               case CHAR: 
528                 value = (signed char) va_arg (args, int);
529                 break;
530               case SHORT:
531                 value = (short) va_arg (args, int);
532                 break;
533               case INT:
534                 value = va_arg (args, int);
535                 break;
536               case LONG:
537                 value = va_arg (args, long);
538                 break;
539               case LONGLONG:
540                 value = va_arg (args, long long);
541                 break;
542               case PTRDIFFT:
543                 value = va_arg (args, ptrdiff_t);
544                 break;
545               case SIZET:
546                 value = va_arg (args, size_t);
547                 break;
548               default:
549                 NOT_REACHED ();
550               }
551
552             format_integer (value < 0 ? -value : value,
553                             value < 0, &base_d, &c, output, aux);
554           }
555           break;
556           
557         case 'o':
558         case 'u':
559         case 'x':
560         case 'X':
561           {
562             /* Unsigned integer conversions. */
563             uintmax_t value;
564             const struct integer_base *b;
565
566             switch (c.type) 
567               {
568               case CHAR: 
569                 value = (unsigned char) va_arg (args, unsigned);
570                 break;
571               case SHORT:
572                 value = (unsigned short) va_arg (args, unsigned);
573                 break;
574               case INT:
575                 value = va_arg (args, unsigned);
576                 break;
577               case LONG:
578                 value = va_arg (args, unsigned long);
579                 break;
580               case LONGLONG:
581                 value = va_arg (args, unsigned long long);
582                 break;
583               case PTRDIFFT:
584                 value = va_arg (args, ptrdiff_t);
585                 break;
586               case SIZET:
587                 value = va_arg (args, size_t);
588                 break;
589               default:
590                 NOT_REACHED ();
591               }
592
593             switch (*format) 
594               {
595               case 'o': b = &base_o; break;
596               case 'u': b = &base_d; break;
597               case 'x': b = &base_x; break;
598               case 'X': b = &base_X; break;
599               default: NOT_REACHED ();
600               }
601             
602             format_integer (value, false, b, &c, output, aux);
603           }
604           break;
605
606         case 'c': 
607           {
608             /* Treat character as single-character string. */
609             char ch = va_arg (args, int);
610             format_string (&ch, 1, &c, output, aux);
611           }
612           break;
613
614         case 's':
615           {
616             /* String conversion. */
617             const char *s = va_arg (args, char *);
618             if (s == NULL)
619               s = "(null)";
620
621             /* Limit string length according to precision.
622                Note: if c.precision == -1 then strnlen() will get
623                SIZE_MAX for MAXLEN, which is just what we want. */
624             format_string (s, strnlen (s, c.precision), &c, output, aux);
625           }
626           break;
627           
628         case 'p':
629           {
630             /* Pointer conversion.
631                Format non-null pointers as %#x. */
632             void *p = va_arg (args, void *);
633
634             c.flags = POUND;
635             if (p != NULL) 
636               format_integer ((uintptr_t) p, false, &base_x, &c, output, aux);
637             else
638               format_string ("(nil)", 5, &c, output, aux); 
639           }
640           break;
641       
642         case 'f':
643         case 'e':
644         case 'E':
645         case 'g':
646         case 'G':
647         case 'n':
648           /* We don't support floating-point arithmetic,
649              and %n can be part of a security hole. */
650           printf_core ("<<no %%%c in kernel>>", output, aux, *format);
651           break;
652
653         default:
654           printf_core ("<<no %%%c conversion>>", output, aux, *format);
655           break;
656         }
657     }
658 }
659
660 /* Parses conversion option characters starting at FORMAT and
661    initializes C appropriately.  Returns the character in FORMAT
662    that indicates the conversion (e.g. the `d' in `%d').  Uses
663    *ARGS for `*' field widths and precisions. */
664 static const char *
665 parse_conversion (const char *format, struct printf_conversion *c,
666                   va_list *args) 
667 {
668   /* Parse flag characters. */
669   c->flags = 0;
670   for (;;) 
671     {
672       switch (*format++) 
673         {
674         case '-':
675           c->flags |= MINUS;
676           break;
677         case '+':
678           c->flags |= PLUS;
679           break;
680         case ' ':
681           c->flags |= SPACE;
682           break;
683         case '#':
684           c->flags |= POUND;
685           break;
686         case '0':
687           c->flags |= ZERO;
688           break;
689         case '\'':
690           c->flags |= GROUP;
691           break;
692         default:
693           format--;
694           goto not_a_flag;
695         }
696     }
697  not_a_flag:
698   if (c->flags & MINUS)
699     c->flags &= ~ZERO;
700   if (c->flags & PLUS)
701     c->flags &= ~SPACE;
702
703   /* Parse field width. */
704   c->width = 0;
705   if (*format == '*')
706     {
707       format++;
708       c->width = va_arg (*args, int);
709     }
710   else 
711     {
712       for (; isdigit (*format); format++)
713         c->width = c->width * 10 + *format - '0';
714     }
715   if (c->width < 0) 
716     {
717       c->width = -c->width;
718       c->flags |= MINUS;
719     }
720       
721   /* Parse precision. */
722   c->precision = -1;
723   if (*format == '.') 
724     {
725       format++;
726       if (*format == '*') 
727         {
728           format++;
729           c->precision = va_arg (*args, int);
730         }
731       else 
732         {
733           c->precision = 0;
734           for (; isdigit (*format); format++)
735             c->precision = c->precision * 10 + *format - '0';
736         }
737       if (c->precision < 0) 
738         c->precision = -1;
739     }
740   if (c->precision >= 0)
741     c->flags &= ~ZERO;
742
743   /* Parse type. */
744   c->type = INT;
745   switch (*format++) 
746     {
747     case 'h':
748       if (*format == 'h') 
749         {
750           format++;
751           c->type = CHAR;
752         }
753       else
754         c->type = SHORT;
755       break;
756       
757     case 'j':
758       c->type = INTMAX;
759       break;
760
761     case 'l':
762       if (*format == 'l')
763         {
764           format++;
765           c->type = LONGLONG;
766         }
767       else
768         c->type = LONG;
769       break;
770
771     case 't':
772       c->type = PTRDIFFT;
773       break;
774
775     case 'z':
776       c->type = SIZET;
777       break;
778
779     default:
780       format--;
781       break;
782     }
783
784   return format;
785 }
786
787 /* Performs an integer conversion, writing output to OUTPUT with
788    auxiliary data AUX.  The integer converted has absolute value
789    VALUE.  If NEGATIVE is true the value is negative, otherwise
790    positive.  The output will use the given DIGITS, with
791    strlen(DIGITS) indicating the output base.  Details of the
792    conversion are in C. */
793 static void
794 format_integer (uintmax_t value, bool negative, const struct integer_base *b,
795                 const struct printf_conversion *c,
796                 void (*output) (char, void *), void *aux)
797 {
798   char buf[64], *cp;            /* Buffer and current position. */
799   const char *signifier;        /* b->signifier or "". */
800   int precision;                /* Rendered precision. */
801   int pad_cnt;                  /* # of pad characters to fill field width. */
802   int group_cnt;                /* # of digits grouped so far. */
803
804   /* Accumulate digits into buffer.
805      This algorithm produces digits in reverse order, so later we
806      will output the buffer's content in reverse.  This is also
807      the reason that later we append zeros and the sign. */
808   cp = buf;
809   group_cnt = 0;
810   while (value > 0) 
811     {
812       if ((c->flags & GROUP) && group_cnt++ == b->group) 
813         {
814           *cp++ = ',';
815           group_cnt = 0; 
816         }
817       *cp++ = b->digits[value % b->base];
818       value /= b->base;
819     }
820
821   /* Append enough zeros to match precision.
822      If requested precision is 0, then a value of zero is
823      rendered as a null string, otherwise as "0". */
824   precision = c->precision < 0 ? 1 : c->precision;
825   if (precision < 0)
826     precision = 1;
827   while (cp - buf < precision && cp - buf < (int) sizeof buf - 8)
828     *cp++ = '0';
829
830   /* Append sign. */
831   if (c->flags & PLUS)
832     *cp++ = negative ? '-' : '+';
833   else if (c->flags & SPACE)
834     *cp++ = negative ? '-' : ' ';
835   else if (negative)
836     *cp++ = '-';
837
838   /* Calculate number of pad characters to fill field width. */
839   signifier = c->flags & POUND ? b->signifier : "";
840   pad_cnt = c->width - (cp - buf) - strlen (signifier);
841   if (pad_cnt < 0)
842     pad_cnt = 0;
843
844   /* Do output. */
845   if ((c->flags & (MINUS | ZERO)) == 0)
846     output_dup (' ', pad_cnt, output, aux);
847   while (*signifier != '\0')
848     output (*signifier++, aux);
849   if (c->flags & ZERO)
850     output_dup ('0', pad_cnt, output, aux);
851   while (cp > buf)
852     output (*--cp, aux);
853   if (c->flags & MINUS)
854     output_dup (' ', pad_cnt, output, aux);
855 }
856
857 /* Writes CH to OUTPUT with auxiliary data AUX, CNT times. */
858 static void
859 output_dup (char ch, size_t cnt, void (*output) (char, void *), void *aux) 
860 {
861   while (cnt-- > 0)
862     output (ch, aux);
863 }
864
865 /* Formats the LENGTH characters starting at STRING according to
866    the conversion specified in C.  Writes output to OUTPUT with
867    auxiliary data AUX. */
868 static void
869 format_string (const char *string, size_t length,
870                struct printf_conversion *c,
871                void (*output) (char, void *), void *aux) 
872 {
873   if (c->width > 1 && (c->flags & MINUS) == 0)
874     output_dup (' ', c->width - 1, output, aux);
875   while (length-- > 0)
876     output (*string++, aux);
877   if (c->width > 1 && (c->flags & MINUS) != 0)
878     output_dup (' ', c->width - 1, output, aux);
879 }
880
881 /* Wrapper for vprintf_core() that converts varargs into a
882    va_list. */
883 static void
884 printf_core (const char *format,
885              void (*output) (char, void *), void *aux, ...) 
886 {
887   va_list args;
888
889   va_start (args, aux);
890   vprintf_core (format, args, output, aux);
891   va_end (args);
892 }
893 \f
894 /* Dumps the SIZE bytes in BUFFER to the console as hex bytes
895    arranged 16 per line.  If ASCII is true then the corresponding
896    ASCII characters are also rendered alongside. */   
897 void
898 hex_dump (const void *buffer, size_t size, bool ascii)
899 {
900   const size_t n_per_line = 16; /* Maximum bytes per line. */
901   size_t n;                     /* Number of bytes in this line. */
902   const uint8_t *p;             /* Start of current line in buffer. */
903
904   for (p = buffer; p < (uint8_t *) buffer + size; p += n) 
905     {
906       size_t i;
907
908       /* Number of bytes on this line. */
909       n = (uint8_t *) (buffer + size) - p;
910       if (n > n_per_line)
911         n = n_per_line;
912
913       /* Print line. */
914       for (i = 0; i < n; i++) 
915         printk ("%c%02x", i == n_per_line / 2 ? '-' : ' ', (unsigned) p[i]);
916       if (ascii) 
917         {
918           for (; i < n_per_line; i++)
919             printk ("   ");
920           printk (" |");
921           for (i = 0; i < n; i++)
922             printk ("%c", isprint (p[i]) ? p[i] : '.');
923           for (; i < n_per_line; i++)
924             printk (" ");
925           printk ("|");
926         }
927       printk ("\n");
928     }
929 }