00001 #include <stdio.h>
00002
00003 #include <ctype.h>
00004 #include <inttypes.h>
00005 #include <round.h>
00006 #include <stdint.h>
00007 #include <string.h>
00008
00009
00010 struct vsnprintf_aux
00011 {
00012 char *p;
00013 int length;
00014 int max_length;
00015 };
00016
00017 static void vsnprintf_helper (char, void *);
00018
00019
00020
00021
00022
00023
00024
00025
00026 int
00027 vsnprintf (char *buffer, size_t buf_size, const char *format, va_list args)
00028 {
00029
00030 struct vsnprintf_aux aux;
00031 aux.p = buffer;
00032 aux.length = 0;
00033 aux.max_length = buf_size > 0 ? buf_size - 1 : 0;
00034
00035
00036 __vprintf (format, args, vsnprintf_helper, &aux);
00037
00038
00039 if (buf_size > 0)
00040 *aux.p = '\0';
00041
00042 return aux.length;
00043 }
00044
00045
00046 static void
00047 vsnprintf_helper (char ch, void *aux_)
00048 {
00049 struct vsnprintf_aux *aux = aux_;
00050
00051 if (aux->length++ < aux->max_length)
00052 *aux->p++ = ch;
00053 }
00054
00055
00056
00057
00058
00059
00060
00061
00062 int
00063 snprintf (char *buffer, size_t buf_size, const char *format, ...)
00064 {
00065 va_list args;
00066 int retval;
00067
00068 va_start (args, format);
00069 retval = vsnprintf (buffer, buf_size, format, args);
00070 va_end (args);
00071
00072 return retval;
00073 }
00074
00075
00076
00077
00078
00079 int
00080 printf (const char *format, ...)
00081 {
00082 va_list args;
00083 int retval;
00084
00085 va_start (args, format);
00086 retval = vprintf (format, args);
00087 va_end (args);
00088
00089 return retval;
00090 }
00091
00092
00093
00094
00095 struct printf_conversion
00096 {
00097
00098 enum
00099 {
00100 MINUS = 1 << 0,
00101 PLUS = 1 << 1,
00102 SPACE = 1 << 2,
00103 POUND = 1 << 3,
00104 ZERO = 1 << 4,
00105 GROUP = 1 << 5
00106 }
00107 flags;
00108
00109
00110 int width;
00111
00112
00113
00114 int precision;
00115
00116
00117 enum
00118 {
00119 CHAR = 1,
00120 SHORT = 2,
00121 INT = 3,
00122 INTMAX = 4,
00123 LONG = 5,
00124 LONGLONG = 6,
00125 PTRDIFFT = 7,
00126 SIZET = 8
00127 }
00128 type;
00129 };
00130
00131 struct integer_base
00132 {
00133 int base;
00134 const char *digits;
00135 int x;
00136 int group;
00137 };
00138
00139 static const struct integer_base base_d = {10, "0123456789", 0, 3};
00140 static const struct integer_base base_o = {8, "01234567", 0, 3};
00141 static const struct integer_base base_x = {16, "0123456789abcdef", 'x', 4};
00142 static const struct integer_base base_X = {16, "0123456789ABCDEF", 'X', 4};
00143
00144 static const char *parse_conversion (const char *format,
00145 struct printf_conversion *,
00146 va_list *);
00147 static void format_integer (uintmax_t value, bool is_signed, bool negative,
00148 const struct integer_base *,
00149 const struct printf_conversion *,
00150 void (*output) (char, void *), void *aux);
00151 static void output_dup (char ch, size_t cnt,
00152 void (*output) (char, void *), void *aux);
00153 static void format_string (const char *string, int length,
00154 struct printf_conversion *,
00155 void (*output) (char, void *), void *aux);
00156
00157 void
00158 __vprintf (const char *format, va_list args,
00159 void (*output) (char, void *), void *aux)
00160 {
00161 for (; *format != '\0'; format++)
00162 {
00163 struct printf_conversion c;
00164
00165
00166 if (*format != '%')
00167 {
00168 output (*format, aux);
00169 continue;
00170 }
00171 format++;
00172
00173
00174 if (*format == '%')
00175 {
00176 output ('%', aux);
00177 continue;
00178 }
00179
00180
00181 format = parse_conversion (format, &c, &args);
00182
00183
00184 switch (*format)
00185 {
00186 case 'd':
00187 case 'i':
00188 {
00189
00190 intmax_t value;
00191
00192 switch (c.type)
00193 {
00194 case CHAR:
00195 value = (signed char) va_arg (args, int);
00196 break;
00197 case SHORT:
00198 value = (short) va_arg (args, int);
00199 break;
00200 case INT:
00201 value = va_arg (args, int);
00202 break;
00203 case INTMAX:
00204 value = va_arg (args, intmax_t);
00205 break;
00206 case LONG:
00207 value = va_arg (args, long);
00208 break;
00209 case LONGLONG:
00210 value = va_arg (args, long long);
00211 break;
00212 case PTRDIFFT:
00213 value = va_arg (args, ptrdiff_t);
00214 break;
00215 case SIZET:
00216 value = va_arg (args, size_t);
00217 if (value > SIZE_MAX / 2)
00218 value = value - SIZE_MAX - 1;
00219 break;
00220 default:
00221 NOT_REACHED ();
00222 }
00223
00224 format_integer (value < 0 ? -value : value,
00225 true, value < 0, &base_d, &c, output, aux);
00226 }
00227 break;
00228
00229 case 'o':
00230 case 'u':
00231 case 'x':
00232 case 'X':
00233 {
00234
00235 uintmax_t value;
00236 const struct integer_base *b;
00237
00238 switch (c.type)
00239 {
00240 case CHAR:
00241 value = (unsigned char) va_arg (args, unsigned);
00242 break;
00243 case SHORT:
00244 value = (unsigned short) va_arg (args, unsigned);
00245 break;
00246 case INT:
00247 value = va_arg (args, unsigned);
00248 break;
00249 case INTMAX:
00250 value = va_arg (args, uintmax_t);
00251 break;
00252 case LONG:
00253 value = va_arg (args, unsigned long);
00254 break;
00255 case LONGLONG:
00256 value = va_arg (args, unsigned long long);
00257 break;
00258 case PTRDIFFT:
00259 value = va_arg (args, ptrdiff_t);
00260 #if UINTMAX_MAX != PTRDIFF_MAX
00261 value &= ((uintmax_t) PTRDIFF_MAX << 1) | 1;
00262 #endif
00263 break;
00264 case SIZET:
00265 value = va_arg (args, size_t);
00266 break;
00267 default:
00268 NOT_REACHED ();
00269 }
00270
00271 switch (*format)
00272 {
00273 case 'o': b = &base_o; break;
00274 case 'u': b = &base_d; break;
00275 case 'x': b = &base_x; break;
00276 case 'X': b = &base_X; break;
00277 default: NOT_REACHED ();
00278 }
00279
00280 format_integer (value, false, false, b, &c, output, aux);
00281 }
00282 break;
00283
00284 case 'c':
00285 {
00286
00287 char ch = va_arg (args, int);
00288 format_string (&ch, 1, &c, output, aux);
00289 }
00290 break;
00291
00292 case 's':
00293 {
00294
00295 const char *s = va_arg (args, char *);
00296 if (s == NULL)
00297 s = "(null)";
00298
00299
00300
00301
00302 format_string (s, strnlen (s, c.precision), &c, output, aux);
00303 }
00304 break;
00305
00306 case 'p':
00307 {
00308
00309
00310 void *p = va_arg (args, void *);
00311
00312 c.flags = POUND;
00313 format_integer ((uintptr_t) p, false, false,
00314 &base_x, &c, output, aux);
00315 }
00316 break;
00317
00318 case 'f':
00319 case 'e':
00320 case 'E':
00321 case 'g':
00322 case 'G':
00323 case 'n':
00324
00325
00326 __printf ("<<no %%%c in kernel>>", output, aux, *format);
00327 break;
00328
00329 default:
00330 __printf ("<<no %%%c conversion>>", output, aux, *format);
00331 break;
00332 }
00333 }
00334 }
00335
00336
00337
00338
00339
00340 static const char *
00341 parse_conversion (const char *format, struct printf_conversion *c,
00342 va_list *args)
00343 {
00344
00345 c->flags = 0;
00346 for (;;)
00347 {
00348 switch (*format++)
00349 {
00350 case '-':
00351 c->flags |= MINUS;
00352 break;
00353 case '+':
00354 c->flags |= PLUS;
00355 break;
00356 case ' ':
00357 c->flags |= SPACE;
00358 break;
00359 case '#':
00360 c->flags |= POUND;
00361 break;
00362 case '0':
00363 c->flags |= ZERO;
00364 break;
00365 case '\'':
00366 c->flags |= GROUP;
00367 break;
00368 default:
00369 format--;
00370 goto not_a_flag;
00371 }
00372 }
00373 not_a_flag:
00374 if (c->flags & MINUS)
00375 c->flags &= ~ZERO;
00376 if (c->flags & PLUS)
00377 c->flags &= ~SPACE;
00378
00379
00380 c->width = 0;
00381 if (*format == '*')
00382 {
00383 format++;
00384 c->width = va_arg (*args, int);
00385 }
00386 else
00387 {
00388 for (; isdigit (*format); format++)
00389 c->width = c->width * 10 + *format - '0';
00390 }
00391 if (c->width < 0)
00392 {
00393 c->width = -c->width;
00394 c->flags |= MINUS;
00395 }
00396
00397
00398 c->precision = -1;
00399 if (*format == '.')
00400 {
00401 format++;
00402 if (*format == '*')
00403 {
00404 format++;
00405 c->precision = va_arg (*args, int);
00406 }
00407 else
00408 {
00409 c->precision = 0;
00410 for (; isdigit (*format); format++)
00411 c->precision = c->precision * 10 + *format - '0';
00412 }
00413 if (c->precision < 0)
00414 c->precision = -1;
00415 }
00416 if (c->precision >= 0)
00417 c->flags &= ~ZERO;
00418
00419
00420 c->type = INT;
00421 switch (*format++)
00422 {
00423 case 'h':
00424 if (*format == 'h')
00425 {
00426 format++;
00427 c->type = CHAR;
00428 }
00429 else
00430 c->type = SHORT;
00431 break;
00432
00433 case 'j':
00434 c->type = INTMAX;
00435 break;
00436
00437 case 'l':
00438 if (*format == 'l')
00439 {
00440 format++;
00441 c->type = LONGLONG;
00442 }
00443 else
00444 c->type = LONG;
00445 break;
00446
00447 case 't':
00448 c->type = PTRDIFFT;
00449 break;
00450
00451 case 'z':
00452 c->type = SIZET;
00453 break;
00454
00455 default:
00456 format--;
00457 break;
00458 }
00459
00460 return format;
00461 }
00462
00463
00464
00465
00466
00467
00468
00469
00470 static void
00471 format_integer (uintmax_t value, bool is_signed, bool negative,
00472 const struct integer_base *b,
00473 const struct printf_conversion *c,
00474 void (*output) (char, void *), void *aux)
00475 {
00476 char buf[64], *cp;
00477 int x;
00478 int sign;
00479 int precision;
00480 int pad_cnt;
00481 int digit_cnt;
00482
00483
00484
00485
00486 sign = 0;
00487 if (is_signed)
00488 {
00489 if (c->flags & PLUS)
00490 sign = negative ? '-' : '+';
00491 else if (c->flags & SPACE)
00492 sign = negative ? '-' : ' ';
00493 else if (negative)
00494 sign = '-';
00495 }
00496
00497
00498
00499
00500 x = (c->flags & POUND) && value ? b->x : 0;
00501
00502
00503
00504
00505 cp = buf;
00506 digit_cnt = 0;
00507 while (value > 0)
00508 {
00509 if ((c->flags & GROUP) && digit_cnt > 0 && digit_cnt % b->group == 0)
00510 *cp++ = ',';
00511 *cp++ = b->digits[value % b->base];
00512 value /= b->base;
00513 digit_cnt++;
00514 }
00515
00516
00517
00518
00519
00520
00521 precision = c->precision < 0 ? 1 : c->precision;
00522 while (cp - buf < precision && cp < buf + sizeof buf - 1)
00523 *cp++ = '0';
00524 if ((c->flags & POUND) && b->base == 8 && (cp == buf || cp[-1] != '0'))
00525 *cp++ = '0';
00526
00527
00528 pad_cnt = c->width - (cp - buf) - (x ? 2 : 0) - (sign != 0);
00529 if (pad_cnt < 0)
00530 pad_cnt = 0;
00531
00532
00533 if ((c->flags & (MINUS | ZERO)) == 0)
00534 output_dup (' ', pad_cnt, output, aux);
00535 if (sign)
00536 output (sign, aux);
00537 if (x)
00538 {
00539 output ('0', aux);
00540 output (x, aux);
00541 }
00542 if (c->flags & ZERO)
00543 output_dup ('0', pad_cnt, output, aux);
00544 while (cp > buf)
00545 output (*--cp, aux);
00546 if (c->flags & MINUS)
00547 output_dup (' ', pad_cnt, output, aux);
00548 }
00549
00550
00551 static void
00552 output_dup (char ch, size_t cnt, void (*output) (char, void *), void *aux)
00553 {
00554 while (cnt-- > 0)
00555 output (ch, aux);
00556 }
00557
00558
00559
00560
00561 static void
00562 format_string (const char *string, int length,
00563 struct printf_conversion *c,
00564 void (*output) (char, void *), void *aux)
00565 {
00566 int i;
00567 if (c->width > length && (c->flags & MINUS) == 0)
00568 output_dup (' ', c->width - length, output, aux);
00569 for (i = 0; i < length; i++)
00570 output (string[i], aux);
00571 if (c->width > length && (c->flags & MINUS) != 0)
00572 output_dup (' ', c->width - length, output, aux);
00573 }
00574
00575
00576
00577 void
00578 __printf (const char *format,
00579 void (*output) (char, void *), void *aux, ...)
00580 {
00581 va_list args;
00582
00583 va_start (args, aux);
00584 __vprintf (format, args, output, aux);
00585 va_end (args);
00586 }
00587
00588
00589
00590
00591
00592
00593 void
00594 hex_dump (uintptr_t ofs, const void *buf_, size_t size, bool ascii)
00595 {
00596 const uint8_t *buf = buf_;
00597 const size_t per_line = 16;
00598
00599 while (size > 0)
00600 {
00601 size_t start, end, n;
00602 size_t i;
00603
00604
00605 start = ofs % per_line;
00606 end = per_line;
00607 if (end - start > size)
00608 end = start + size;
00609 n = end - start;
00610
00611
00612 printf ("%08jx ", (uintmax_t) ROUND_DOWN (ofs, per_line));
00613 for (i = 0; i < start; i++)
00614 printf (" ");
00615 for (; i < end; i++)
00616 printf ("%02hhx%c",
00617 buf[i - start], i == per_line / 2 - 1? '-' : ' ');
00618 if (ascii)
00619 {
00620 for (; i < per_line; i++)
00621 printf (" ");
00622 printf ("|");
00623 for (i = 0; i < start; i++)
00624 printf (" ");
00625 for (; i < end; i++)
00626 printf ("%c",
00627 isprint (buf[i - start]) ? buf[i - start] : '.');
00628 for (; i < per_line; i++)
00629 printf (" ");
00630 printf ("|");
00631 }
00632 printf ("\n");
00633
00634 ofs += n;
00635 buf += n;
00636 size -= n;
00637 }
00638 }
00639
00640
00641
00642 void
00643 print_human_readable_size (uint64_t size)
00644 {
00645 if (size == 1)
00646 printf ("1 byte");
00647 else
00648 {
00649 static const char *factors[] = {"bytes", "kB", "MB", "GB", "TB", NULL};
00650 const char **fp;
00651
00652 for (fp = factors; size >= 1024 && fp[1] != NULL; fp++)
00653 size /= 1024;
00654 printf ("%"PRIu64" %s", size, *fp);
00655 }
00656 }