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 {
BufferBuffer33 Buffer(char* buffer, size_t size)
34 :
35 fCurrent(buffer),
36 fSize(size),
37 fBytesWritten(0)
38 {
39 }
40
BytesWrittenBuffer41 size_t BytesWritten() const
42 {
43 return fBytesWritten;
44 }
45
PutCharacterBuffer46 void PutCharacter(char c)
47 {
48 if (fBytesWritten < fSize) {
49 *fCurrent = c;
50 fCurrent++;
51 }
52
53 fBytesWritten++;
54 }
55
PutPaddingBuffer56 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
PutStringBuffer70 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
NullTerminateBuffer84 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
skip_atoi(const char ** s)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
do_div(uint64 * _number,uint32 base)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
sign_symbol(int flags,bool negative)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
number(Buffer & outBuffer,uint64 num,uint32 base,int size,int precision,int flags)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
floating(Buffer & outBuffer,double value,int fieldWidth,int flags)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
vsnprintf(char * buffer,size_t bufferSize,const char * format,va_list args)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
vsprintf(char * buffer,const char * format,va_list args)481 vsprintf(char *buffer, const char *format, va_list args)
482 {
483 return vsnprintf(buffer, ~0UL, format, args);
484 }
485
486
487 int
snprintf(char * buffer,size_t bufferSize,const char * format,...)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
sprintf(char * buffer,const char * format,...)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