1/* 2 * Copyright Patrick Powell 1995 3 * This code is based on code written by Patrick Powell (papowell@astart.com) 4 * It may be used for any purpose as long as this notice remains intact 5 * on all source code distributions 6 */ 7 8/************************************************************** 9 * Original: 10 * Patrick Powell Tue Apr 11 09:48:21 PDT 1995 11 * A bombproof version of doprnt (dopr) included. 12 * Sigh. This sort of thing is always nasty do deal with. Note that 13 * the version here does not include floating point... 14 * 15 * snprintf() is used instead of sprintf() as it does limit checks 16 * for string length. This covers a nasty loophole. 17 * 18 * The other functions are there to prevent NULL pointers from 19 * causing nast effects. 20 * 21 * More Recently: 22 * Brandon Long <blong@fiction.net> 9/15/96 for mutt 0.43 23 * This was ugly. It is still ugly. I opted out of floating point 24 * numbers, but the formatter understands just about everything 25 * from the normal C string format, at least as far as I can tell from 26 * the Solaris 2.5 printf(3S) man page. 27 * 28 * Brandon Long <blong@fiction.net> 10/22/97 for mutt 0.87.1 29 * Ok, added some minimal floating point support, which means this 30 * probably requires libm on most operating systems. Don't yet 31 * support the exponent (e,E) and sigfig (g,G). Also, fmtint() 32 * was pretty badly broken, it just wasn't being exercised in ways 33 * which showed it, so that's been fixed. Also, formated the code 34 * to mutt conventions, and removed dead code left over from the 35 * original. Also, there is now a builtin-test, just compile with: 36 * gcc -DTEST_SNPRINTF -o snprintf snprintf.c -lm 37 * and run snprintf for results. 38 * 39 * Thomas Roessler <roessler@guug.de> 01/27/98 for mutt 0.89i 40 * The PGP code was using unsigned hexadecimal formats. 41 * Unfortunately, unsigned formats simply didn't work. 42 * 43 * Michael Elkins <me@cs.hmc.edu> 03/05/98 for mutt 0.90.8 44 * The original code assumed that both snprintf() and vsnprintf() were 45 * missing. Some systems only have snprintf() but not vsnprintf(), so 46 * the code is now broken down under HAVE_SNPRINTF and HAVE_VSNPRINTF. 47 * 48 * Andrew Tridgell (tridge@samba.org) Oct 1998 49 * fixed handling of %.0f 50 * added test for HAVE_LONG_DOUBLE 51 * 52 * tridge@samba.org, idra@samba.org, April 2001 53 * got rid of fcvt code (twas buggy and made testing harder) 54 * added C99 semantics 55 * 56 * date: 2002/12/19 19:56:31; author: herb; state: Exp; lines: +2 -0 57 * actually print args for %g and %e 58 * 59 * date: 2002/06/03 13:37:52; author: jmcd; state: Exp; lines: +8 -0 60 * Since includes.h isn't included here, VA_COPY has to be defined here. I don't 61 * see any include file that is guaranteed to be here, so I'm defining it 62 * locally. Fixes AIX and Solaris builds. 63 * 64 * date: 2002/06/03 03:07:24; author: tridge; state: Exp; lines: +5 -13 65 * put the ifdef for HAVE_VA_COPY in one place rather than in lots of 66 * functions 67 * 68 * date: 2002/05/17 14:51:22; author: jmcd; state: Exp; lines: +21 -4 69 * Fix usage of va_list passed as an arg. Use __va_copy before using it 70 * when it exists. 71 * 72 * date: 2002/04/16 22:38:04; author: idra; state: Exp; lines: +20 -14 73 * Fix incorrect zpadlen handling in fmtfp. 74 * Thanks to Ollie Oldham <ollie.oldham@metro-optix.com> for spotting it. 75 * few mods to make it easier to compile the tests. 76 * addedd the "Ollie" test to the floating point ones. 77 * 78 * Martin Pool (mbp@samba.org) April 2003 79 * Remove NO_CONFIG_H so that the test case can be built within a source 80 * tree with less trouble. 81 * Remove unnecessary SAFE_FREE() definition. 82 * 83 * Martin Pool (mbp@samba.org) May 2003 84 * Put in a prototype for dummy_snprintf() to quiet compiler warnings. 85 * 86 * Move #endif to make sure VA_COPY, LDOUBLE, etc are defined even 87 * if the C library has some snprintf functions already. 88 * 89 * Damien Miller (djm@mindrot.org) Jan 2007 90 * Fix integer overflows in return value. 91 * Make formatting quite a bit faster by inlining dopr_outch() 92 * 93 **************************************************************/ 94 95#ifdef BARRELFISH 96#include <barrelfish/barrelfish.h> 97#include <skb/skb.h> 98#include <if/skb_defs.h> 99#include <barrelfish/core_state_arch.h> 100#include <octopus/capability_storage.h> 101#include "skb_internal.h" 102#endif 103 104#define CAP_STORAGE_IDENT "cid_" 105 106 107#if defined(BROKEN_SNPRINTF) /* For those with broken snprintf() */ 108# undef HAVE_SNPRINTF 109# undef HAVE_VSNPRINTF 110#endif 111 112#if !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) 113 114#include <ctype.h> 115#include <stdarg.h> 116#include <stdlib.h> 117#include <string.h> 118#include <limits.h> 119#include <errno.h> 120#include <stdint.h> 121 122#ifdef HAVE_LONG_DOUBLE 123# define LDOUBLE long double 124#else 125# define LDOUBLE double 126#endif 127 128# define LLONG long long 129 130/* 131 * dopr(): poor man's version of doprintf 132 */ 133 134/* format read states */ 135#define DP_S_DEFAULT 0 136#define DP_S_FLAGS 1 137#define DP_S_MIN 2 138#define DP_S_DOT 3 139#define DP_S_MAX 4 140#define DP_S_MOD 5 141#define DP_S_CONV 6 142#define DP_S_DONE 7 143 144/* format flags - Bits */ 145#define DP_F_MINUS (1 << 0) 146#define DP_F_PLUS (1 << 1) 147#define DP_F_SPACE (1 << 2) 148#define DP_F_NUM (1 << 3) 149#define DP_F_ZERO (1 << 4) 150#define DP_F_UP (1 << 5) 151#define DP_F_UNSIGNED (1 << 6) 152 153/* Conversion Flags */ 154#define DP_C_SHORT 1 155#define DP_C_LONG 2 156#define DP_C_LDOUBLE 3 157#define DP_C_LLONG 4 158#define DP_C_SIZE 5 159#define DP_C_INTMAX 6 160#define DP_C_CHAR 7 161 162#define char_to_int(p) ((p)- '0') 163#ifndef MAX 164# define MAX(p,q) (((p) >= (q)) ? (p) : (q)) 165#endif 166 167#define DOPR_OUTCH(buf, pos, buflen, thechar) \ 168 do { \ 169 if (pos + 1 >= INT_MAX) { \ 170 errno = ERANGE; \ 171 return -1; \ 172 } \ 173 if (pos < buflen) \ 174 buf[pos] = thechar; \ 175 (pos)++; \ 176 } while (0) 177 178static int dopr(char *buffer, size_t maxlen, const char *format, 179 va_list args_in); 180static int fmtstr(char *buffer, size_t *currlen, size_t maxlen, 181 char *value, int flags, int min, int max); 182static int fmtint(char *buffer, size_t *currlen, size_t maxlen, 183 intmax_t value, int base, int min, int max, int flags); 184static int fmtfp(char *buffer, size_t *currlen, size_t maxlen, 185 LDOUBLE fvalue, int min, int max, int flags); 186static int fmtcap(char *buffer, size_t *currlen, size_t maxlen, struct capref c); 187 188static int 189dopr(char *buffer, size_t maxlen, const char *format, va_list args_in) 190{ 191 char ch; 192 intmax_t value; 193 LDOUBLE fvalue; 194 char *strvalue; 195 int min; 196 int max; 197 int state; 198 int flags; 199 int cflags; 200 size_t currlen; 201 va_list args; 202 203 va_copy(args, args_in); 204 205 state = DP_S_DEFAULT; 206 currlen = flags = cflags = min = 0; 207 max = -1; 208 ch = *format++; 209 210 while (state != DP_S_DONE) { 211 if (ch == '\0') 212 state = DP_S_DONE; 213 214 switch(state) { 215 case DP_S_DEFAULT: 216 if (ch == '%') 217 state = DP_S_FLAGS; 218 else 219 DOPR_OUTCH(buffer, currlen, maxlen, ch); 220 ch = *format++; 221 break; 222 case DP_S_FLAGS: 223 switch (ch) { 224 case '-': 225 flags |= DP_F_MINUS; 226 ch = *format++; 227 break; 228 case '+': 229 flags |= DP_F_PLUS; 230 ch = *format++; 231 break; 232 case ' ': 233 flags |= DP_F_SPACE; 234 ch = *format++; 235 break; 236 case '#': 237 flags |= DP_F_NUM; 238 ch = *format++; 239 break; 240 case '0': 241 flags |= DP_F_ZERO; 242 ch = *format++; 243 break; 244 default: 245 state = DP_S_MIN; 246 break; 247 } 248 break; 249 case DP_S_MIN: 250 if (isdigit((unsigned char)ch)) { 251 min = 10*min + char_to_int (ch); 252 ch = *format++; 253 } else if (ch == '*') { 254 min = va_arg (args, int); 255 ch = *format++; 256 state = DP_S_DOT; 257 } else { 258 state = DP_S_DOT; 259 } 260 break; 261 case DP_S_DOT: 262 if (ch == '.') { 263 state = DP_S_MAX; 264 ch = *format++; 265 } else { 266 state = DP_S_MOD; 267 } 268 break; 269 case DP_S_MAX: 270 if (isdigit((unsigned char)ch)) { 271 if (max < 0) 272 max = 0; 273 max = 10*max + char_to_int (ch); 274 ch = *format++; 275 } else if (ch == '*') { 276 max = va_arg (args, int); 277 ch = *format++; 278 state = DP_S_MOD; 279 } else { 280 state = DP_S_MOD; 281 } 282 break; 283 case DP_S_MOD: 284 switch (ch) { 285 case 'h': 286 cflags = DP_C_SHORT; 287 ch = *format++; 288 if (ch == 'h') { 289 //cflags = DP_C_SHORT; 290 ch = *format++; 291 } 292 break; 293 case 'j': 294 cflags = DP_C_INTMAX; 295 ch = *format++; 296 break; 297 case 'l': 298 cflags = DP_C_LONG; 299 ch = *format++; 300 if (ch == 'l') { /* It's a long long */ 301 cflags = DP_C_LLONG; 302 ch = *format++; 303 } 304 break; 305 case 'L': 306 cflags = DP_C_LDOUBLE; 307 ch = *format++; 308 break; 309 case 'z': 310 cflags = DP_C_SIZE; 311 ch = *format++; 312 break; 313 default: 314 break; 315 } 316 state = DP_S_CONV; 317 break; 318 case DP_S_CONV: 319 switch (ch) { 320 case 'd': 321 case 'i': 322 if (cflags == DP_C_SHORT) 323 value = va_arg (args, int); 324 else if (cflags == DP_C_LONG) 325 value = va_arg (args, long int); 326 else if (cflags == DP_C_LLONG) 327 value = va_arg (args, LLONG); 328 else if (cflags == DP_C_SIZE) 329 value = va_arg (args, ssize_t); 330 else if (cflags == DP_C_INTMAX) 331 value = va_arg (args, intmax_t); 332 else 333 value = va_arg (args, int); 334 if (fmtint(buffer, &currlen, maxlen, 335 value, 10, min, max, flags) == -1) 336 return -1; 337 break; 338 case 'o': 339 flags |= DP_F_UNSIGNED; 340 if (cflags == DP_C_SHORT) 341 value = va_arg (args, unsigned int); 342 else if (cflags == DP_C_LONG) 343 value = (long)va_arg (args, unsigned long int); 344 else if (cflags == DP_C_LLONG) 345 value = (long)va_arg (args, unsigned LLONG); 346 else if (cflags == DP_C_SIZE) 347 value = va_arg (args, size_t); 348#ifdef notyet 349 else if (cflags == DP_C_INTMAX) 350 value = va_arg (args, uintmax_t); 351#endif 352 else 353 value = (long)va_arg (args, unsigned int); 354 if (fmtint(buffer, &currlen, maxlen, value, 355 8, min, max, flags) == -1) 356 return -1; 357 break; 358 case 'u': 359 flags |= DP_F_UNSIGNED; 360 if (cflags == DP_C_SHORT) 361 value = va_arg (args, unsigned int); 362 else if (cflags == DP_C_LONG) 363 value = (long)va_arg (args, unsigned long int); 364 else if (cflags == DP_C_LLONG) 365 value = (LLONG)va_arg (args, unsigned LLONG); 366 else if (cflags == DP_C_SIZE) 367 value = va_arg (args, size_t); 368#ifdef notyet 369 else if (cflags == DP_C_INTMAX) 370 value = va_arg (args, uintmax_t); 371#endif 372 else 373 value = (long)va_arg (args, unsigned int); 374 if (fmtint(buffer, &currlen, maxlen, value, 375 10, min, max, flags) == -1) 376 return -1; 377 break; 378 case 'X': 379 flags |= DP_F_UP; 380 case 'x': 381 flags |= DP_F_UNSIGNED; 382 if (cflags == DP_C_SHORT) 383 value = va_arg (args, unsigned int); 384 else if (cflags == DP_C_LONG) 385 value = (long)va_arg (args, unsigned long int); 386 else if (cflags == DP_C_LLONG) 387 value = (LLONG)va_arg (args, unsigned LLONG); 388 else if (cflags == DP_C_SIZE) 389 value = va_arg (args, size_t); 390#ifdef notyet 391 else if (cflags == DP_C_INTMAX) 392 value = va_arg (args, uintmax_t); 393#endif 394 else 395 value = (long)va_arg (args, unsigned int); 396 if (fmtint(buffer, &currlen, maxlen, value, 397 16, min, max, flags) == -1) 398 return -1; 399 break; 400 case 'f': 401 if (cflags == DP_C_LDOUBLE) 402 fvalue = va_arg (args, LDOUBLE); 403 else 404 fvalue = va_arg (args, double); 405 if (fmtfp(buffer, &currlen, maxlen, fvalue, 406 min, max, flags) == -1) 407 return -1; 408 break; 409 case 'E': 410 flags |= DP_F_UP; 411 case 'e': 412 if (cflags == DP_C_LDOUBLE) 413 fvalue = va_arg (args, LDOUBLE); 414 else 415 fvalue = va_arg (args, double); 416 if (fmtfp(buffer, &currlen, maxlen, fvalue, 417 min, max, flags) == -1) 418 return -1; 419 break; 420 case 'G': 421 flags |= DP_F_UP; 422 case 'g': 423 if (cflags == DP_C_LDOUBLE) 424 fvalue = va_arg (args, LDOUBLE); 425 else 426 fvalue = va_arg (args, double); 427 if (fmtfp(buffer, &currlen, maxlen, fvalue, 428 min, max, flags) == -1) 429 return -1; 430 break; 431 case 'c': 432 DOPR_OUTCH(buffer, currlen, maxlen, 433 va_arg (args, int)); 434 break; 435 case 's': 436 strvalue = va_arg (args, char *); 437 if (!strvalue) strvalue = "(NULL)"; 438 if (max == -1) { 439 max = strlen(strvalue); 440 } 441 if (min > 0 && max >= 0 && min > max) max = min; 442 if (fmtstr(buffer, &currlen, maxlen, 443 strvalue, flags, min, max) == -1) 444 return -1; 445 break; 446 case 'p': 447 strvalue = va_arg (args, void *); 448 if (fmtint(buffer, &currlen, maxlen, 449 (long) strvalue, 16, min, max, flags) == -1) 450 return -1; 451 break; 452#if we_dont_want_this_in_openssh 453 case 'n': 454 if (cflags == DP_C_SHORT) { 455 short int *num; 456 num = va_arg (args, short int *); 457 *num = currlen; 458 } else if (cflags == DP_C_LONG) { 459 long int *num; 460 num = va_arg (args, long int *); 461 *num = (long int)currlen; 462 } else if (cflags == DP_C_LLONG) { 463 LLONG *num; 464 num = va_arg (args, LLONG *); 465 *num = (LLONG)currlen; 466 } else if (cflags == DP_C_SIZE) { 467 ssize_t *num; 468 num = va_arg (args, ssize_t *); 469 *num = (ssize_t)currlen; 470 } else if (cflags == DP_C_INTMAX) { 471 intmax_t *num; 472 num = va_arg (args, intmax_t *); 473 *num = (intmax_t)currlen; 474 } else { 475 int *num; 476 num = va_arg (args, int *); 477 *num = currlen; 478 } 479 break; 480#endif 481 case '%': 482 DOPR_OUTCH(buffer, currlen, maxlen, ch); 483 break; 484 case 'w': 485 /* not supported yet, treat as next char */ 486 ch = *format++; 487 break; 488 case 'Q': 489 /* Barrelfish specific capref type */ 490 if (fmtcap(buffer, &currlen, maxlen, va_arg(args, struct capref)) == -1) 491 return -1; 492 break; 493 default: 494 /* Unknown, skip */ 495 break; 496 } 497 ch = *format++; 498 state = DP_S_DEFAULT; 499 flags = cflags = min = 0; 500 max = -1; 501 break; 502 case DP_S_DONE: 503 break; 504 default: 505 /* hmm? */ 506 break; /* some picky compilers need this */ 507 } 508 } 509 if (maxlen != 0) { 510 if (currlen < maxlen - 1) 511 buffer[currlen] = '\0'; 512 else if (maxlen > 0) 513 buffer[maxlen - 1] = '\0'; 514 } 515 516 return currlen < INT_MAX ? (int)currlen : -1; 517} 518 519static int 520fmtstr(char *buffer, size_t *currlen, size_t maxlen, 521 char *value, int flags, int min, int max) 522{ 523 int padlen, strln; /* amount to pad */ 524 int cnt = 0; 525 526//#define DEBUG_SNPRINTF 1 527#ifdef DEBUG_SNPRINTF 528 printf("fmtstr min=%d max=%d s=[%s]\n", min, max, value); 529#endif 530 if (value == 0) { 531 value = "<NULL>"; 532 } 533 534 for (strln = 0; strln < max && value[strln]; ++strln); /* strlen */ 535 padlen = min - strln; 536 if (padlen < 0) 537 padlen = 0; 538 if (flags & DP_F_MINUS) 539 padlen = -padlen; /* Left Justify */ 540 541 while ((padlen > 0) && (cnt < max)) { 542 DOPR_OUTCH(buffer, *currlen, maxlen, ' '); 543 --padlen; 544 ++cnt; 545 } 546 while (*value && (cnt < max)) { 547 DOPR_OUTCH(buffer, *currlen, maxlen, *value); 548 value++; 549 ++cnt; 550 } 551 while ((padlen < 0) && (cnt < max)) { 552 DOPR_OUTCH(buffer, *currlen, maxlen, ' '); 553 ++padlen; 554 ++cnt; 555 } 556 return 0; 557} 558 559// Replaces %C with the identifers returned from oct_sput_capability 560static int fmtcap(char *buffer, size_t *currlen, size_t maxlen, struct capref c) 561{ 562 char* retkey = NULL; 563 errval_t err = oct_sput_capability(CAP_STORAGE_IDENT, c, &retkey); 564 if (err_is_fail(err)) { 565 USER_PANIC_ERR(err, "Can't save the cap in the storage?"); 566 return -1; 567 } 568 assert(retkey != NULL); 569 //printf("Stored capability using oct_put_capability in '%s'.\n", retkey); 570 571 while (*retkey) { 572 DOPR_OUTCH(buffer, *currlen, maxlen, *retkey); 573 retkey++; 574 } 575 576 return 0; 577} 578 579/* Have to handle DP_F_NUM (ie 0x and 0 alternates) */ 580 581static int 582fmtint(char *buffer, size_t *currlen, size_t maxlen, 583 intmax_t value, int base, int min, int max, int flags) 584{ 585 int signvalue = 0; 586 unsigned LLONG uvalue; 587 char convert[20]; 588 int place = 0; 589 int spadlen = 0; /* amount to space pad */ 590 int zpadlen = 0; /* amount to zero pad */ 591 int caps = 0; 592 593 if (max < 0) 594 max = 0; 595 596 uvalue = value; 597 598 if(!(flags & DP_F_UNSIGNED)) { 599 if( value < 0 ) { 600 signvalue = '-'; 601 uvalue = -value; 602 } else { 603 if (flags & DP_F_PLUS) /* Do a sign (+/i) */ 604 signvalue = '+'; 605 else if (flags & DP_F_SPACE) 606 signvalue = ' '; 607 } 608 } 609 610 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ 611 612 do { 613 convert[place++] = 614 (caps? "0123456789ABCDEF":"0123456789abcdef") 615 [uvalue % (unsigned)base ]; 616 uvalue = (uvalue / (unsigned)base ); 617 } while(uvalue && (place < 20)); 618 if (place == 20) place--; 619 convert[place] = 0; 620 621 zpadlen = max - place; 622 spadlen = min - MAX (max, place) - (signvalue ? 1 : 0); 623 if (zpadlen < 0) zpadlen = 0; 624 if (spadlen < 0) spadlen = 0; 625 if (flags & DP_F_ZERO) { 626 zpadlen = MAX(zpadlen, spadlen); 627 spadlen = 0; 628 } 629 if (flags & DP_F_MINUS) 630 spadlen = -spadlen; /* Left Justifty */ 631 632#ifdef DEBUG_SNPRINTF 633 printf("zpad: %d, spad: %d, min: %d, max: %d, place: %d\n", 634 zpadlen, spadlen, min, max, place); 635#endif 636 637 /* Spaces */ 638 while (spadlen > 0) { 639 DOPR_OUTCH(buffer, *currlen, maxlen, ' '); 640 --spadlen; 641 } 642 643 /* Sign */ 644 if (signvalue) 645 DOPR_OUTCH(buffer, *currlen, maxlen, signvalue); 646 647 /* Zeros */ 648 if (zpadlen > 0) { 649 while (zpadlen > 0) { 650 DOPR_OUTCH(buffer, *currlen, maxlen, '0'); 651 --zpadlen; 652 } 653 } 654 655 /* Digits */ 656 while (place > 0) { 657 --place; 658 DOPR_OUTCH(buffer, *currlen, maxlen, convert[place]); 659 } 660 661 /* Left Justified spaces */ 662 while (spadlen < 0) { 663 DOPR_OUTCH(buffer, *currlen, maxlen, ' '); 664 ++spadlen; 665 } 666 return 0; 667} 668 669static LDOUBLE abs_val(LDOUBLE value) 670{ 671 LDOUBLE result = value; 672 673 if (value < 0) 674 result = -value; 675 676 return result; 677} 678 679static LDOUBLE POW10(int val) 680{ 681 LDOUBLE result = 1; 682 683 while (val) { 684 result *= 10; 685 val--; 686 } 687 688 return result; 689} 690 691static LLONG ROUND(LDOUBLE value) 692{ 693 LLONG intpart; 694 695 intpart = (LLONG)value; 696 value = value - intpart; 697 if (value >= 0.5) intpart++; 698 699 return intpart; 700} 701 702/* a replacement for modf that doesn't need the math library. Should 703 be portable, but slow */ 704static double my_modf(double x0, double *iptr) 705{ 706 int i; 707 long l; 708 double x = x0; 709 double f = 1.0; 710 711 for (i=0;i<100;i++) { 712 l = (long)x; 713 if (l <= (x+1) && l >= (x-1)) break; 714 x *= 0.1; 715 f *= 10.0; 716 } 717 718 if (i == 100) { 719 /* 720 * yikes! the number is beyond what we can handle. 721 * What do we do? 722 */ 723 (*iptr) = 0; 724 return 0; 725 } 726 727 if (i != 0) { 728 double i2; 729 double ret; 730 731 ret = my_modf(x0-l*f, &i2); 732 (*iptr) = l*f + i2; 733 return ret; 734 } 735 736 (*iptr) = l; 737 return x - (*iptr); 738} 739 740 741static int 742fmtfp (char *buffer, size_t *currlen, size_t maxlen, 743 LDOUBLE fvalue, int min, int max, int flags) 744{ 745 int signvalue = 0; 746 double ufvalue; 747 char iconvert[311]; 748 char fconvert[311]; 749 int iplace = 0; 750 int fplace = 0; 751 int padlen = 0; /* amount to pad */ 752 int zpadlen = 0; 753 int caps = 0; 754 int idx; 755 double intpart; 756 double fracpart; 757 double temp; 758 759 /* 760 * AIX manpage says the default is 0, but Solaris says the default 761 * is 6, and sprintf on AIX defaults to 6 762 */ 763 if (max < 0) 764 max = 6; 765 766 ufvalue = abs_val (fvalue); 767 768 if (fvalue < 0) { 769 signvalue = '-'; 770 } else { 771 if (flags & DP_F_PLUS) { /* Do a sign (+/i) */ 772 signvalue = '+'; 773 } else { 774 if (flags & DP_F_SPACE) 775 signvalue = ' '; 776 } 777 } 778 779#if 0 780 if (flags & DP_F_UP) caps = 1; /* Should characters be upper case? */ 781#endif 782 783#if 0 784 if (max == 0) ufvalue += 0.5; /* if max = 0 we must round */ 785#endif 786 787 /* 788 * Sorry, we only support 16 digits past the decimal because of our 789 * conversion method 790 */ 791 if (max > 16) 792 max = 16; 793 794 /* We "cheat" by converting the fractional part to integer by 795 * multiplying by a factor of 10 796 */ 797 798 temp = ufvalue; 799 my_modf(temp, &intpart); 800 801 fracpart = ROUND((POW10(max)) * (ufvalue - intpart)); 802 803 if (fracpart >= POW10(max)) { 804 intpart++; 805 fracpart -= POW10(max); 806 } 807 808 /* Convert integer part */ 809 do { 810 temp = intpart*0.1; 811 my_modf(temp, &intpart); 812 idx = (int) ((temp -intpart +0.05)* 10.0); 813 /* idx = (int) (((double)(temp*0.1) -intpart +0.05) *10.0); */ 814 /* printf ("%llf, %f, %x\n", temp, intpart, idx); */ 815 iconvert[iplace++] = 816 (caps? "0123456789ABCDEF":"0123456789abcdef")[idx]; 817 } while (intpart && (iplace < 311)); 818 if (iplace == 311) iplace--; 819 iconvert[iplace] = 0; 820 821 /* Convert fractional part */ 822 if (fracpart) 823 { 824 do { 825 temp = fracpart*0.1; 826 my_modf(temp, &fracpart); 827 idx = (int) ((temp -fracpart +0.05)* 10.0); 828 /* idx = (int) ((((temp/10) -fracpart) +0.05) *10); */ 829 /* printf ("%lf, %lf, %ld\n", temp, fracpart, idx ); */ 830 fconvert[fplace++] = 831 (caps? "0123456789ABCDEF":"0123456789abcdef")[idx]; 832 } while(fracpart && (fplace < 311)); 833 if (fplace == 311) fplace--; 834 } 835 fconvert[fplace] = 0; 836 837 /* -1 for decimal point, another -1 if we are printing a sign */ 838 padlen = min - iplace - max - 1 - ((signvalue) ? 1 : 0); 839 zpadlen = max - fplace; 840 if (zpadlen < 0) zpadlen = 0; 841 if (padlen < 0) 842 padlen = 0; 843 if (flags & DP_F_MINUS) 844 padlen = -padlen; /* Left Justifty */ 845 846 if ((flags & DP_F_ZERO) && (padlen > 0)) { 847 if (signvalue) { 848 DOPR_OUTCH(buffer, *currlen, maxlen, signvalue); 849 --padlen; 850 signvalue = 0; 851 } 852 while (padlen > 0) { 853 DOPR_OUTCH(buffer, *currlen, maxlen, '0'); 854 --padlen; 855 } 856 } 857 while (padlen > 0) { 858 DOPR_OUTCH(buffer, *currlen, maxlen, ' '); 859 --padlen; 860 } 861 if (signvalue) 862 DOPR_OUTCH(buffer, *currlen, maxlen, signvalue); 863 864 while (iplace > 0) { 865 --iplace; 866 DOPR_OUTCH(buffer, *currlen, maxlen, iconvert[iplace]); 867 } 868 869#ifdef DEBUG_SNPRINTF 870 printf("fmtfp: fplace=%d zpadlen=%d\n", fplace, zpadlen); 871#endif 872 873 /* 874 * Decimal point. This should probably use locale to find the correct 875 * char to print out. 876 */ 877 if (max > 0) { 878 DOPR_OUTCH(buffer, *currlen, maxlen, '.'); 879 880 while (zpadlen > 0) { 881 DOPR_OUTCH(buffer, *currlen, maxlen, '0'); 882 --zpadlen; 883 } 884 885 while (fplace > 0) { 886 --fplace; 887 DOPR_OUTCH(buffer, *currlen, maxlen, fconvert[fplace]); 888 } 889 } 890 891 while (padlen < 0) { 892 DOPR_OUTCH(buffer, *currlen, maxlen, ' '); 893 ++padlen; 894 } 895 return 0; 896} 897#endif /* !defined(HAVE_SNPRINTF) || !defined(HAVE_VSNPRINTF) */ 898 899int 900skb_vsnprintf (char *str, size_t count, const char *fmt, va_list args) 901{ 902 return dopr(str, count, fmt, args); 903} 904 905int 906skb_snprintf(char *str, size_t count, const char *fmt, ...) 907{ 908 size_t ret; 909 va_list ap; 910 911 va_start(ap, fmt); 912 ret = vsnprintf(str, count, fmt, ap); 913 va_end(ap); 914 return ret; 915} 916