migrate substitution keywords to SVN
[reactos.git] / reactos / ntoskrnl / rtl / sprintf.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/rtl/sprintf.c
6 * PURPOSE: Single byte sprintf functions
7 * PROGRAMMERS: David Welch
8 * Eric Kohl
9 *
10 */
11
12 /*
13 * linux/lib/vsprintf.c
14 *
15 * Copyright (C) 1991, 1992 Linus Torvalds
16 */
17
18 /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
19 /*
20 * Wirzenius wrote this portably, Torvalds fucked it up :-)
21 */
22
23 #include <ntoskrnl.h>
24 #include <internal/ctype.h>
25 #include <internal/debug.h>
26
27
28 #define ZEROPAD 1 /* pad with zero */
29 #define SIGN 2 /* unsigned/signed long */
30 #define PLUS 4 /* show plus */
31 #define SPACE 8 /* space if plus */
32 #define LEFT 16 /* left justified */
33 #define SPECIAL 32 /* 0x */
34 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
35
36
37 #if defined(__GNUC__)
38
39 #define do_div(n,base) ({ \
40 int __res; \
41 __res = ((unsigned long long) n) % (unsigned) base; \
42 n = ((unsigned long long) n) / (unsigned) base; \
43 __res; })
44
45 #else /* __GNUC__ */
46 /* n /= base, "returns" remainder */
47 __inline int int_do_div(__int64* n, int base)
48 {
49 int __res = (int)(((unsigned __int64)*n) % (unsigned) base);
50 *n = (int)(((unsigned __int64)*n) / (unsigned) base);
51 return __res;
52 }
53 #define do_div(n,base) int_do_div(&n, base)
54
55 #endif /* __GNUC__ */
56
57
58 static int skip_atoi(const char **s)
59 {
60 int i=0;
61
62 while (isdigit(**s))
63 i = i*10 + *((*s)++) - '0';
64 return i;
65 }
66
67
68 static char *
69 #if defined(__GNUC__)
70 number(char *buf, char *end, long long num, int base, int size, int precision, int type)
71 #else
72 number(char *buf, char *end, __int64 num, int base, int size, int precision, int type)
73 #endif
74 {
75 char c,sign,tmp[66];
76 const char *digits;
77 const char *small_digits = "0123456789abcdefghijklmnopqrstuvwxyz";
78 const char *large_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
79 int i;
80
81 digits = (type & LARGE) ? large_digits : small_digits;
82 if (type & LEFT)
83 type &= ~ZEROPAD;
84 if (base < 2 || base > 36)
85 return 0;
86 c = (type & ZEROPAD) ? '0' : ' ';
87 sign = 0;
88 if (type & SIGN) {
89 if (num < 0) {
90 sign = '-';
91 num = -num;
92 size--;
93 } else if (type & PLUS) {
94 sign = '+';
95 size--;
96 } else if (type & SPACE) {
97 sign = ' ';
98 size--;
99 }
100 }
101 if (type & SPECIAL) {
102 if (base == 16)
103 size -= 2;
104 else if (base == 8)
105 size--;
106 }
107 i = 0;
108 if (num == 0)
109 tmp[i++]='0';
110 else while (num != 0)
111 tmp[i++] = digits[do_div(num,base)];
112 if (i > precision)
113 precision = i;
114 size -= precision;
115 if (!(type&(ZEROPAD+LEFT))) {
116 while(size-->0) {
117 if (buf <= end)
118 *buf = ' ';
119 ++buf;
120 }
121 }
122 if (sign) {
123 if (buf <= end)
124 *buf = sign;
125 ++buf;
126 }
127 if (type & SPECIAL) {
128 if (base==8) {
129 if (buf <= end)
130 *buf = '0';
131 ++buf;
132 } else if (base==16) {
133 if (buf <= end)
134 *buf = '0';
135 ++buf;
136 if (buf <= end)
137 *buf = digits[33];
138 ++buf;
139 }
140 }
141 if (!(type & LEFT)) {
142 while (size-- > 0) {
143 if (buf <= end)
144 *buf = c;
145 ++buf;
146 }
147 }
148 while (i < precision--) {
149 if (buf <= end)
150 *buf = '0';
151 ++buf;
152 }
153 while (i-- > 0) {
154 if (buf <= end)
155 *buf = tmp[i];
156 ++buf;
157 }
158 while (size-- > 0) {
159 if (buf <= end)
160 *buf = ' ';
161 ++buf;
162 }
163 return buf;
164 }
165
166 static char*
167 string(char* buf, char* end, const char* s, int len, int field_width, int precision, int flags)
168 {
169 int i;
170 if (s == NULL)
171 {
172 s = "<NULL>";
173 len = 6;
174 }
175 else
176 {
177 if (len == -1)
178 {
179 len = 0;
180 while ((unsigned int)len < (unsigned int)precision && s[len])
181 len++;
182 }
183 else
184 {
185 if ((unsigned int)len > (unsigned int)precision)
186 len = precision;
187 }
188 }
189 if (!(flags & LEFT))
190 while (len < field_width--)
191 {
192 if (buf <= end)
193 *buf = ' ';
194 ++buf;
195 }
196 for (i = 0; i < len; ++i)
197 {
198 if (buf <= end)
199 *buf = *s++;
200 ++buf;
201 }
202 while (len < field_width--)
203 {
204 if (buf <= end)
205 *buf = ' ';
206 ++buf;
207 }
208 return buf;
209 }
210
211 static char*
212 stringw(char* buf, char* end, const wchar_t* sw, int len, int field_width, int precision, int flags)
213 {
214 int i;
215 if (sw == NULL)
216 {
217 sw = L"<NULL>";
218 len = 6;
219 }
220 else
221 {
222 if (len == -1)
223 {
224 len = 0;
225 while ((unsigned int)len < (unsigned int)precision && sw[len])
226 len++;
227 }
228 else
229 {
230 if ((unsigned int)len > (unsigned int)precision)
231 len = precision;
232 }
233 }
234 if (!(flags & LEFT))
235 while (len < field_width--)
236 {
237 if (buf <= end)
238 *buf = ' ';
239 ++buf;
240 }
241 for (i = 0; i < len; ++i)
242 {
243 if (buf <= end)
244 *buf = (unsigned char)(*sw++);
245 ++buf;
246 }
247 while (len < field_width--)
248 {
249 if (buf <= end)
250 *buf = ' ';
251 ++buf;
252 }
253 return buf;
254 }
255
256 /*
257 * @implemented
258 */
259 int _vsnprintf(char *buf, size_t cnt, const char *fmt, va_list args)
260 {
261 int len;
262 #if defined(__GNUC__)
263 unsigned long long num;
264 #else
265 unsigned __int64 num;
266 #endif
267 int base;
268 char *str, *end;
269 const char *s;
270 const wchar_t *sw;
271
272 int flags; /* flags to number() */
273
274 int field_width; /* width of output field */
275 int precision; /* min. # of digits for integers; max
276 number of chars for from string */
277 int qualifier; /* 'h', 'l', 'L', 'I' or 'w' for integer fields */
278
279 str = buf;
280 end = buf + cnt - 1;
281 if (end < buf - 1) {
282 end = ((void *) -1);
283 cnt = end - buf + 1;
284 }
285
286 for ( ; *fmt ; ++fmt) {
287 if (*fmt != '%') {
288 if (str <= end)
289 *str = *fmt;
290 ++str;
291 continue;
292 }
293
294 /* process flags */
295 flags = 0;
296 repeat:
297 ++fmt; /* this also skips first '%' */
298 switch (*fmt) {
299 case '-': flags |= LEFT; goto repeat;
300 case '+': flags |= PLUS; goto repeat;
301 case ' ': flags |= SPACE; goto repeat;
302 case '#': flags |= SPECIAL; goto repeat;
303 case '0': flags |= ZEROPAD; goto repeat;
304 }
305
306 /* get field width */
307 field_width = -1;
308 if (isdigit(*fmt))
309 field_width = skip_atoi(&fmt);
310 else if (*fmt == '*') {
311 ++fmt;
312 /* it's the next argument */
313 field_width = va_arg(args, int);
314 if (field_width < 0) {
315 field_width = -field_width;
316 flags |= LEFT;
317 }
318 }
319
320 /* get the precision */
321 precision = -1;
322 if (*fmt == '.') {
323 ++fmt;
324 if (isdigit(*fmt))
325 precision = skip_atoi(&fmt);
326 else if (*fmt == '*') {
327 ++fmt;
328 /* it's the next argument */
329 precision = va_arg(args, int);
330 }
331 if (precision < 0)
332 precision = 0;
333 }
334
335 /* get the conversion qualifier */
336 qualifier = -1;
337 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'w') {
338 qualifier = *fmt;
339 ++fmt;
340 } else if (*fmt == 'I' && *(fmt+1) == '6' && *(fmt+2) == '4') {
341 qualifier = *fmt;
342 fmt += 3;
343 }
344
345 /* default base */
346 base = 10;
347
348 switch (*fmt) {
349 case 'c': /* finished */
350 if (!(flags & LEFT))
351 while (--field_width > 0)
352 {
353 if (str <= end)
354 *str = ' ';
355 ++str;
356 }
357 if (qualifier == 'l' || qualifier == 'w')
358 {
359 if (str <= end)
360 *str = (unsigned char)(wchar_t) va_arg(args, int);
361 ++str;
362 }
363 else
364 {
365 if (str <= end)
366 *str = (unsigned char) va_arg(args, int);
367 ++str;
368 }
369 while (--field_width > 0)
370 {
371 if (str <= end)
372 *str = ' ';
373 ++str;
374 }
375 continue;
376
377 case 'C': /* finished */
378 if (!(flags & LEFT))
379 while (--field_width > 0)
380 {
381 if (str <= end)
382 *str = ' ';
383 ++str;
384 }
385 if (qualifier == 'h')
386 {
387 if (str <= end)
388 *str = (unsigned char) va_arg(args, int);
389 ++str;
390 }
391 else
392 {
393 if (str <= end)
394 *str = (unsigned char)(wchar_t) va_arg(args, int);
395 ++str;
396 }
397 while (--field_width > 0)
398 {
399 if (str <= end)
400 *str = ' ';
401 ++str;
402 }
403 continue;
404
405 case 's': /* finished */
406 if (qualifier == 'l' || qualifier == 'w') {
407 /* print unicode string */
408 sw = va_arg(args, wchar_t *);
409 str = stringw(str, end, sw, -1, field_width, precision, flags);
410 } else {
411 /* print ascii string */
412 s = va_arg(args, char *);
413 str = string(str, end, s, -1, field_width, precision, flags);
414 }
415 continue;
416
417 case 'S':
418 if (qualifier == 'h') {
419 /* print ascii string */
420 s = va_arg(args, char *);
421 str = string(str, end, s, -1, field_width, precision, flags);
422 } else {
423 /* print unicode string */
424 sw = va_arg(args, wchar_t *);
425 str = stringw(str, end, sw, -1, field_width, precision, flags);
426 }
427 continue;
428
429 case 'Z':
430 if (qualifier == 'w') {
431 /* print counted unicode string */
432 PUNICODE_STRING pus = va_arg(args, PUNICODE_STRING);
433 if ((pus == NULL) || (pus->Buffer == NULL)) {
434 sw = NULL;
435 len = -1;
436 } else {
437 sw = pus->Buffer;
438 len = pus->Length / sizeof(WCHAR);
439 }
440 str = stringw(str, end, sw, len, field_width, precision, flags);
441 } else {
442 /* print counted ascii string */
443 PANSI_STRING pus = va_arg(args, PANSI_STRING);
444 if ((pus == NULL) || (pus->Buffer == NULL)) {
445 s = NULL;
446 len = -1;
447 } else {
448 s = pus->Buffer;
449 len = pus->Length;
450 }
451 str = string(str, end, s, len, field_width, precision, flags);
452 }
453 continue;
454
455 case 'p':
456 if (field_width == -1) {
457 field_width = 2 * sizeof(void *);
458 flags |= ZEROPAD;
459 }
460 str = number(str, end,
461 (unsigned long) va_arg(args, void *),
462 16, field_width, precision, flags);
463 continue;
464
465 case 'n':
466 /* FIXME: What does C99 say about the overflow case here? */
467 if (qualifier == 'l') {
468 long * ip = va_arg(args, long *);
469 *ip = (str - buf);
470 } else {
471 int * ip = va_arg(args, int *);
472 *ip = (str - buf);
473 }
474 continue;
475
476 /* integer number formats - set up the flags and "break" */
477 case 'o':
478 base = 8;
479 break;
480
481 case 'b':
482 base = 2;
483 break;
484
485 case 'X':
486 flags |= LARGE;
487 case 'x':
488 base = 16;
489 break;
490
491 case 'd':
492 case 'i':
493 flags |= SIGN;
494 case 'u':
495 break;
496
497 default:
498 if (*fmt != '%')
499 {
500 if (str <= end)
501 *str = '%';
502 ++str;
503 }
504 if (*fmt)
505 {
506 if (str <= end)
507 *str = *fmt;
508 ++str;
509 }
510 else
511 --fmt;
512 continue;
513 }
514
515 if (qualifier == 'I')
516 #if defined(__GNUC__)
517 num = va_arg(args, unsigned long long);
518 #else
519 num = va_arg(args, unsigned __int64);
520 #endif
521 else if (qualifier == 'l') {
522 if (flags & SIGN)
523 num = va_arg(args, long);
524 else
525 num = va_arg(args, unsigned long);
526 }
527 else if (qualifier == 'h') {
528 if (flags & SIGN)
529 num = va_arg(args, int);
530 else
531 num = va_arg(args, unsigned int);
532 }
533 else {
534 if (flags & SIGN)
535 num = va_arg(args, int);
536 else
537 num = va_arg(args, unsigned int);
538 }
539 str = number(str, end, num, base, field_width, precision, flags);
540 }
541
542 if (str <= end)
543 *str = '\0';
544 else if (cnt > 0)
545 /* don't write out a null byte if the buf size is zero */
546 *end = '\0';
547
548 return str-buf;
549 }
550
551
552 /*
553 * @implemented
554 */
555 int sprintf(char * buf, const char *fmt, ...)
556 {
557 va_list args;
558 int i;
559
560 va_start(args, fmt);
561 i=_vsnprintf(buf,INT_MAX,fmt,args);
562 va_end(args);
563 return i;
564 }
565
566
567 /*
568 * @implemented
569 */
570 int _snprintf(char * buf, size_t cnt, const char *fmt, ...)
571 {
572 va_list args;
573 int i;
574
575 va_start(args, fmt);
576 i=_vsnprintf(buf,cnt,fmt,args);
577 va_end(args);
578 return i;
579 }
580
581
582 /*
583 * @implemented
584 */
585 int vsprintf(char *buf, const char *fmt, va_list args)
586 {
587 return _vsnprintf(buf,INT_MAX,fmt,args);
588 }
589
590 /* EOF */