1 /* 2 * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Copyright 2003-2008, Axel Dörfler. All rights reserved. 4 * Distributed under the terms of the MIT license. 5 * 6 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 7 * Distributed under the terms of the NewOS License. 8 */ 9 10 11 #include <SupportDefs.h> 12 13 #include <ctype.h> 14 #include <stdarg.h> 15 #include <stdio.h> 16 #include <string.h> 17 18 #include <algorithm> 19 20 21 #define ZEROPAD 1 /* pad with zero */ 22 #define SIGN 2 /* unsigned/signed long */ 23 #define PLUS 4 /* show plus */ 24 #define SPACE 8 /* space if plus */ 25 #define LEFT 16 /* left justified */ 26 #define SPECIAL 32 /* 0x */ 27 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ 28 29 #define FLOATING_SUPPORT 30 31 32 struct Buffer { 33 Buffer(char* buffer, size_t size) 34 : 35 fCurrent(buffer), 36 fSize(size), 37 fBytesWritten(0) 38 { 39 } 40 41 size_t BytesWritten() const 42 { 43 return fBytesWritten; 44 } 45 46 void PutCharacter(char c) 47 { 48 if (fBytesWritten < fSize) { 49 *fCurrent = c; 50 fCurrent++; 51 } 52 53 fBytesWritten++; 54 } 55 56 void PutPadding(int32 count) 57 { 58 if (count <= 0) 59 return; 60 61 if (fBytesWritten < fSize) { 62 int32 toWrite = std::min(fSize - fBytesWritten, (size_t)count); 63 while (--toWrite >= 0) 64 *fCurrent++ = ' '; 65 } 66 67 fBytesWritten += count; 68 } 69 70 void PutString(const char *source, int32 length) 71 { 72 if (length <= 0) 73 return; 74 75 if (fBytesWritten < fSize) { 76 int32 toWrite = std::min(fSize - fBytesWritten, (size_t)length); 77 memcpy(fCurrent, source, toWrite); 78 fCurrent += toWrite; 79 } 80 81 fBytesWritten += length; 82 } 83 84 void NullTerminate() 85 { 86 if (fBytesWritten < fSize) 87 *fCurrent = '\0'; 88 else if (fSize > 0) 89 fCurrent[-1] = '\0'; 90 } 91 92 private: 93 char* fCurrent; 94 size_t fSize; 95 size_t fBytesWritten; 96 }; 97 98 99 static int 100 skip_atoi(const char **s) 101 { 102 int i = 0; 103 104 while (isdigit(**s)) 105 i = i*10 + *((*s)++) - '0'; 106 107 return i; 108 } 109 110 111 static uint64 112 do_div(uint64 *_number, uint32 base) 113 { 114 uint64 result = *_number % (uint64)base; 115 *_number = *_number / (uint64)base; 116 117 return result; 118 } 119 120 121 static char 122 sign_symbol(int flags, bool negative) 123 { 124 if ((flags & SIGN) == 0) 125 return '\0'; 126 127 if (negative) 128 return '-'; 129 else if ((flags & PLUS) != 0) 130 return '+'; 131 else if ((flags & SPACE) != 0) 132 return ' '; 133 134 return '\0'; 135 } 136 137 138 static void 139 number(Buffer& outBuffer, uint64 num, uint32 base, int size, 140 int precision, int flags) 141 { 142 const char *digits = "0123456789abcdefghijklmnopqrstuvwxyz"; 143 char c, sign, tmp[66]; 144 int i; 145 146 if (flags & LARGE) 147 digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 148 if (flags & LEFT) 149 flags &= ~ZEROPAD; 150 if (base < 2 || base > 36) 151 return; 152 153 c = (flags & ZEROPAD) ? '0' : ' '; 154 155 if (flags & SIGN) { 156 sign = sign_symbol(flags, (int64)num < 0); 157 if ((int64)num < 0) 158 num = -(int64)num; 159 if (sign) 160 size--; 161 } else 162 sign = 0; 163 164 if ((flags & SPECIAL) != 0) { 165 if (base == 16) 166 size -= 2; 167 else if (base == 8) 168 size--; 169 } 170 171 i = 0; 172 if (num == 0) 173 tmp[i++] = '0'; 174 else while (num != 0) 175 tmp[i++] = digits[do_div(&num, base)]; 176 177 if (i > precision) 178 precision = i; 179 size -= precision; 180 181 if (!(flags & (ZEROPAD + LEFT))) { 182 outBuffer.PutPadding(size); 183 size = 0; 184 } 185 if (sign) 186 outBuffer.PutCharacter(sign); 187 188 if ((flags & SPECIAL) != 0) { 189 if (base == 8) 190 outBuffer.PutCharacter('0'); 191 else if (base == 16) { 192 outBuffer.PutCharacter('0'); 193 outBuffer.PutCharacter(digits[33]); 194 } 195 } 196 197 if (!(flags & LEFT)) { 198 while (size-- > 0) 199 outBuffer.PutCharacter(c); 200 } 201 while (i < precision--) 202 outBuffer.PutCharacter('0'); 203 while (i-- > 0) 204 outBuffer.PutCharacter(tmp[i]); 205 206 outBuffer.PutPadding(size); 207 } 208 209 210 #ifdef FLOATING_SUPPORT 211 /*! 212 This is a very basic floating point to string conversion routine. 213 It prints up to 3 fraction digits, and doesn't support any precision arguments. 214 It's just here for your convenience so that you can use it for debug output. 215 */ 216 static void 217 floating(Buffer& outBuffer, double value, int fieldWidth, int flags) 218 { 219 char buffer[66]; 220 uint64 fraction; 221 uint64 integer; 222 int32 length = 0; 223 char sign; 224 225 sign = sign_symbol(flags, value < 0.0); 226 if (value < 0.0) 227 value = -value; 228 229 fraction = (uint64)(value * 1000) % 1000; 230 integer = (uint64)value; 231 232 // put fraction part, if any 233 234 if (fraction != 0) { 235 bool first = true; 236 while (fraction != 0) { 237 int digit = do_div(&fraction, 10); 238 if (!first || digit > 0) { 239 buffer[length++] = '0' + digit; 240 first = false; 241 } 242 } 243 244 buffer[length++] = '.'; 245 } 246 247 // put integer part 248 249 if (integer == 0) { 250 buffer[length++] = '0'; 251 } else { 252 while (integer != 0) 253 buffer[length++] = '0' + do_div(&integer, 10); 254 } 255 256 // write back to string 257 258 if (!(flags & LEFT)) 259 outBuffer.PutPadding(fieldWidth); 260 261 if (sign) 262 outBuffer.PutCharacter(sign); 263 264 while (length-- > 0) 265 outBuffer.PutCharacter(buffer[length]); 266 267 if ((flags & LEFT) != 0) 268 outBuffer.PutPadding(fieldWidth); 269 } 270 #endif // FLOATING_SUPPORT 271 272 273 int 274 vsnprintf(char *buffer, size_t bufferSize, const char *format, va_list args) 275 { 276 uint64 num; 277 int base; 278 int flags; /* flags to number() */ 279 int fieldWidth; /* width of output field */ 280 int precision; 281 /* min. # of digits for integers; max number of chars for from string */ 282 int qualifier; /* 'h', 'l', or 'L' for integer fields */ 283 284 Buffer outBuffer(buffer, bufferSize); 285 286 for (; format[0]; format++) { 287 if (format[0] != '%') { 288 outBuffer.PutCharacter(format[0]); 289 continue; 290 } 291 292 /* process flags */ 293 294 flags = 0; 295 296 repeat: 297 format++; 298 /* this also skips first '%' */ 299 switch (format[0]) { 300 case '-': flags |= LEFT; goto repeat; 301 case '+': flags |= PLUS; goto repeat; 302 case ' ': flags |= SPACE; goto repeat; 303 case '#': flags |= SPECIAL; goto repeat; 304 case '0': flags |= ZEROPAD; goto repeat; 305 306 case '%': 307 outBuffer.PutCharacter(format[0]); 308 continue; 309 } 310 311 /* get field width */ 312 313 fieldWidth = -1; 314 if (isdigit(*format)) 315 fieldWidth = skip_atoi(&format); 316 else if (format[0] == '*') { 317 format++; 318 /* it's the next argument */ 319 fieldWidth = va_arg(args, int); 320 if (fieldWidth < 0) { 321 fieldWidth = -fieldWidth; 322 flags |= LEFT; 323 } 324 } 325 326 /* get the precision */ 327 328 precision = -1; 329 if (format[0] == '.') { 330 format++; 331 if (isdigit(*format)) 332 precision = skip_atoi(&format); 333 else if (format[0] == '*') { 334 format++; 335 /* it's the next argument */ 336 precision = va_arg(args, int); 337 } 338 if (precision < 0) 339 precision = 0; 340 } 341 342 /* get the conversion qualifier */ 343 344 qualifier = -1; 345 if (format[0] == 'h' || format[0] == 'L' || format[0] == 'z') { 346 qualifier = *format++; 347 } else if (format[0] == 'l') { 348 format++; 349 if (format[0] == 'l') { 350 qualifier = 'L'; 351 format++; 352 } else 353 qualifier = 'l'; 354 } 355 356 /* default base */ 357 base = 10; 358 359 switch (format[0]) { 360 case 'c': 361 if (!(flags & LEFT)) 362 outBuffer.PutPadding(fieldWidth - 1); 363 364 outBuffer.PutCharacter((char)va_arg(args, int)); 365 366 if ((flags & LEFT) != 0) 367 outBuffer.PutPadding(fieldWidth - 1); 368 continue; 369 370 case 's': 371 { 372 const char *argument = va_arg(args, char *); 373 int32 length; 374 375 if (argument == NULL) 376 argument = "<NULL>"; 377 378 length = strnlen(argument, precision); 379 fieldWidth -= length; 380 381 if (!(flags & LEFT)) 382 outBuffer.PutPadding(fieldWidth); 383 384 outBuffer.PutString(argument, length); 385 386 if ((flags & LEFT) != 0) 387 outBuffer.PutPadding(fieldWidth); 388 continue; 389 } 390 391 #ifdef FLOATING_SUPPORT 392 case 'f': 393 case 'F': 394 case 'g': 395 case 'G': 396 { 397 double value = va_arg(args, double); 398 floating(outBuffer, value, fieldWidth, flags | SIGN); 399 continue; 400 } 401 #endif // FLOATING_SUPPORT 402 403 case 'p': 404 if (fieldWidth == -1) { 405 fieldWidth = 2*sizeof(void *); 406 flags |= ZEROPAD; 407 } 408 409 outBuffer.PutString("0x", 2); 410 number(outBuffer, (addr_t)va_arg(args, void *), 16, fieldWidth, 411 precision, flags); 412 continue; 413 414 case 'n': 415 if (qualifier == 'l') { 416 long *ip = va_arg(args, long *); 417 *ip = outBuffer.BytesWritten(); 418 } else { 419 int *ip = va_arg(args, int *); 420 *ip = outBuffer.BytesWritten(); 421 } 422 continue; 423 424 /* integer number formats - set up the flags and "break" */ 425 case 'o': 426 base = 8; 427 break; 428 429 case 'X': 430 flags |= LARGE; 431 case 'x': 432 base = 16; 433 break; 434 435 case 'd': 436 case 'i': 437 flags |= SIGN; 438 case 'u': 439 break; 440 441 default: 442 if (format[0] != '%') 443 outBuffer.PutCharacter('%'); 444 445 if (!format[0]) 446 goto out; 447 448 outBuffer.PutCharacter(format[0]); 449 continue; 450 } 451 452 if (qualifier == 'L') 453 num = va_arg(args, unsigned long long); 454 else if (qualifier == 'l') { 455 num = va_arg(args, unsigned long); 456 if ((flags & SIGN) != 0) 457 num = (long)num; 458 } else if (qualifier == 'z') { 459 num = va_arg(args, size_t); 460 if ((flags & SIGN) != 0) 461 num = (long)num; 462 } else if (qualifier == 'h') { 463 num = (unsigned short)va_arg(args, int); 464 if ((flags & SIGN) != 0) 465 num = (short)num; 466 } else if ((flags & SIGN) != 0) 467 num = va_arg(args, int); 468 else 469 num = va_arg(args, unsigned int); 470 471 number(outBuffer, num, base, fieldWidth, precision, flags); 472 } 473 474 out: 475 outBuffer.NullTerminate(); 476 return outBuffer.BytesWritten(); 477 } 478 479 480 int 481 vsprintf(char *buffer, const char *format, va_list args) 482 { 483 return vsnprintf(buffer, ~0UL, format, args); 484 } 485 486 487 int 488 snprintf(char *buffer, size_t bufferSize, const char *format, ...) 489 { 490 va_list args; 491 int i; 492 493 va_start(args, format); 494 i = vsnprintf(buffer, bufferSize, format, args); 495 va_end(args); 496 497 return i; 498 } 499 500 501 int 502 sprintf(char *buffer, const char *format, ...) 503 { 504 va_list args; 505 int i; 506 507 va_start(args, format); 508 i = vsnprintf(buffer, ~0UL, format, args); 509 va_end(args); 510 511 return i; 512 } 513 514