fix some advapi crypt winetests
[reactos.git] / reactos / lib / sdk / crt / stdio / lnx_sprintf.c
1 /*
2 * PROGRAMMERS: David Welch
3 * Eric Kohl
4 *
5 * TODO:
6 * - Verify the implementation of '%Z'.
7 */
8
9 /*
10 * linux/lib/vsprintf.c
11 *
12 * Copyright (C) 1991, 1992 Linus Torvalds
13 */
14
15 /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
16 /*
17 * Wirzenius wrote this portably, Torvalds fucked it up :-)
18 */
19
20 #include <precomp.h>
21
22 #include <wchar.h>
23 #include <tchar.h>
24
25 #define ZEROPAD 1 /* pad with zero */
26 #define SIGN 2 /* unsigned/signed long */
27 #define PLUS 4 /* show plus */
28 #define SPACE 8 /* space if plus */
29 #define LEFT 16 /* left justified */
30 #define SPECIAL 32 /* 0x */
31 #define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
32 #define REMOVEHEX 256 /* use 256 as remve 0x frim BASE 16 */
33
34 static
35 __inline
36 int
37 do_div(long long *n, int base)
38 {
39 int a;
40 a = ((unsigned long long) *n) % (unsigned) base;
41 *n = ((unsigned long long) *n) / (unsigned) base;
42 return a;
43 }
44
45
46 static int skip_atoi(const char **s)
47 {
48 int i=0;
49
50 while (isdigit(**s))
51 i = i*10 + *((*s)++) - '0';
52 return i;
53 }
54
55
56 static char *
57 number(char * buf, char * end, long long num, int base, int size, int precision, int type)
58 {
59 char c,sign,tmp[66];
60 const char *digits;
61 const char *small_digits = "0123456789abcdefghijklmnopqrstuvwxyz";
62 const char *large_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
63 int i;
64
65 digits = (type & LARGE) ? large_digits : small_digits;
66 if (type & LEFT)
67 type &= ~ZEROPAD;
68 if (base < 2 || base > 36)
69 return 0;
70 c = (type & ZEROPAD) ? '0' : ' ';
71 sign = 0;
72 if (type & SIGN) {
73 if (num < 0) {
74 sign = '-';
75 num = -num;
76 size--;
77 } else if (type & PLUS) {
78 sign = '+';
79 size--;
80 } else if (type & SPACE) {
81 sign = ' ';
82 size--;
83 }
84 }
85
86 if ((type & SPECIAL) && ((type & REMOVEHEX) == 0)) {
87 if (base == 16)
88 size -= 2;
89
90 }
91 i = 0;
92 if ((num == 0) && (precision !=0))
93 tmp[i++] = '0';
94 else while (num != 0)
95 tmp[i++] = digits[do_div(&num,base)];
96 if (i > precision)
97 precision = i;
98 size -= precision;
99 if (!(type&(ZEROPAD+LEFT))) {
100 while(size-->0) {
101 if (buf <= end)
102 *buf = ' ';
103 ++buf;
104 }
105 }
106 if (sign) {
107 if (buf <= end)
108 *buf = sign;
109 ++buf;
110 }
111
112 if ((type & SPECIAL) && ((type & REMOVEHEX) == 0)) {
113 if (base==16) {
114 if (buf <= end)
115 *buf = '0';
116 ++buf;
117 if (buf <= end)
118 *buf = digits[33];
119 ++buf;
120 }
121 }
122
123 if (!(type & LEFT)) {
124 while (size-- > 0) {
125 if (buf <= end)
126 *buf = c;
127 ++buf;
128 }
129 }
130 while (i < precision--) {
131 if (buf <= end)
132 *buf = '0';
133 ++buf;
134 }
135 while (i-- > 0) {
136 if (buf <= end)
137 *buf = tmp[i];
138 ++buf;
139 }
140 while (size-- > 0) {
141 if (buf <= end)
142 *buf = ' ';
143 ++buf;
144 }
145
146 return buf;
147 }
148
149 static char *
150 numberf(char * buf, char * end, double num, int base, int size, int precision, int type)
151 {
152 char c,sign,tmp[66];
153 const char *digits;
154 const char *small_digits = "0123456789abcdefghijklmnopqrstuvwxyz";
155 const char *large_digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
156 int i;
157 long long x;
158
159 /* FIXME
160 the float version of number is direcly copy of number
161 */
162
163 digits = (type & LARGE) ? large_digits : small_digits;
164 if (type & LEFT)
165 type &= ~ZEROPAD;
166 if (base < 2 || base > 36)
167 return 0;
168 c = (type & ZEROPAD) ? '0' : ' ';
169 sign = 0;
170 if (num < 0) {
171 sign = '-';
172 num = -num;
173 size--;
174 } else if (type & PLUS) {
175 sign = '+';
176 size--;
177 } else if (type & SPACE) {
178 sign = ' ';
179 size--;
180 }
181 if (type & SPECIAL) {
182 if (base == 16)
183 size -= 2;
184 else if (base == 8)
185 size--;
186 }
187 i = 0;
188 if (num == 0)
189 tmp[i++] = '0';
190 else while (num != 0)
191 {
192 x = num;
193 tmp[i++] = digits[do_div(&x,base)];
194 num=x;
195 }
196 if (i > precision)
197 precision = i;
198 size -= precision;
199 if (!(type&(ZEROPAD+LEFT))) {
200 while(size-->0) {
201 if (buf <= end)
202 *buf = ' ';
203 ++buf;
204 }
205 }
206 if (sign) {
207 if (buf <= end)
208 *buf = sign;
209 ++buf;
210 }
211 if (type & SPECIAL) {
212 if (base==8) {
213 if (buf <= end)
214 *buf = '0';
215 ++buf;
216 } else if (base==16) {
217 if (buf <= end)
218 *buf = '0';
219 ++buf;
220 if (buf <= end)
221 *buf = digits[33];
222 ++buf;
223 }
224 }
225 if (!(type & LEFT)) {
226 while (size-- > 0) {
227 if (buf <= end)
228 *buf = c;
229 ++buf;
230 }
231 }
232 if (type & ZEROPAD) {
233 while (i < precision--) {
234 if (buf <= end)
235 *buf = '0';
236 ++buf;
237 }
238 }
239 while (i-- > 0) {
240 if (buf <= end)
241 *buf = tmp[i];
242 ++buf;
243 }
244 while (size-- > 0) {
245 if (buf <= end)
246 *buf = ' ';
247 ++buf;
248 }
249 return buf;
250 }
251
252 static char*
253 string(char* buf, char* end, const char* s, int len, int field_width, int precision, int flags)
254 {
255 int i;
256 char c;
257
258 c = (flags & ZEROPAD) ? '0' : ' ';
259
260 if (s == NULL)
261 {
262 s = "<NULL>";
263 len = 6;
264 }
265 else
266 {
267 if (len == -1)
268 {
269 len = 0;
270 while ((unsigned int)len < (unsigned int)precision && s[len])
271 len++;
272 }
273 else
274 {
275 if ((unsigned int)len > (unsigned int)precision)
276 len = precision;
277 }
278 }
279 if (!(flags & LEFT))
280 while (len < field_width--)
281 {
282 if (buf <= end)
283 *buf = c;
284 ++buf;
285 }
286 for (i = 0; i < len; ++i)
287 {
288 if (buf <= end)
289 *buf = *s++;
290 ++buf;
291 }
292 while (len < field_width--)
293 {
294 if (buf <= end)
295 *buf = ' ';
296 ++buf;
297 }
298 return buf;
299 }
300
301 static char*
302 stringw(char* buf, char* end, const wchar_t* sw, int len, int field_width, int precision, int flags)
303 {
304 int i;
305 char c;
306
307 c = (flags & ZEROPAD) ? '0' : ' ';
308
309 if (sw == NULL)
310 {
311 sw = L"<NULL>";
312 len = 6;
313 }
314 else
315 {
316 if (len == -1)
317 {
318 len = 0;
319 while ((unsigned int)len < (unsigned int)precision && sw[len])
320 len++;
321 }
322 else
323 {
324 if ((unsigned int)len > (unsigned int)precision)
325 len = precision;
326 }
327 }
328 if (!(flags & LEFT))
329 while (len < field_width--)
330 {
331 if (buf <= end)
332 *buf = c;
333 buf++;
334 }
335 for (i = 0; i < len; ++i)
336 {
337 if (buf <= end)
338 *buf = (unsigned char)(*sw++);
339 buf++;
340 }
341 while (len < field_width--)
342 {
343 if (buf <= end)
344 *buf = ' ';
345 buf++;
346 }
347 return buf;
348 }
349
350 /*
351 * @implemented
352 */
353 int __cdecl lnx_vsnprintf(char *buf, size_t cnt, const char *fmt, va_list args)
354 {
355 int len;
356 unsigned long long num;
357 double _double;
358
359 int base;
360 char *str, *end;
361 const char *s;
362 const wchar_t *sw;
363
364 int flags; /* flags to number() */
365
366 int field_width; /* width of output field */
367 int precision; /* min. # of digits for integers; max
368 number of chars for from string */
369 int qualifier; /* 'h', 'l', 'L', 'I' or 'w' for integer fields */
370
371 /* clear the string buffer with zero so we do not need NULL terment it at end */
372
373 str = buf;
374 end = buf + cnt - 1;
375 if (end < buf - 1) {
376 end = ((char *) -1);
377 cnt = end - buf + 1;
378 }
379
380 for ( ; *fmt ; ++fmt) {
381 if (*fmt != '%') {
382 if (str <= end)
383 *str = *fmt;
384 ++str;
385 continue;
386 }
387
388 /* process flags */
389 flags = 0;
390 repeat:
391 ++fmt; /* this also skips first '%' */
392 switch (*fmt) {
393 case '-': flags |= LEFT; goto repeat;
394 case '+': flags |= PLUS; goto repeat;
395 case ' ': flags |= SPACE; goto repeat;
396 case '#': flags |= SPECIAL; goto repeat;
397 case '0': flags |= ZEROPAD; goto repeat;
398 }
399
400 /* get field width */
401 field_width = -1;
402 if (isdigit(*fmt))
403 field_width = skip_atoi(&fmt);
404 else if (*fmt == '*') {
405 ++fmt;
406 /* it's the next argument */
407 field_width = va_arg(args, int);
408 if (field_width < 0) {
409 field_width = -field_width;
410 flags |= LEFT;
411 }
412 }
413
414 /* get the precision */
415 precision = -1;
416 if (*fmt == '.') {
417 ++fmt;
418 if (isdigit(*fmt))
419 precision = skip_atoi(&fmt);
420 else if (*fmt == '*') {
421 ++fmt;
422 /* it's the next argument */
423 precision = va_arg(args, int);
424 }
425 if (precision < 0)
426 precision = 0;
427 }
428
429 /* get the conversion qualifier */
430 qualifier = -1;
431 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || *fmt == 'w') {
432 qualifier = *fmt;
433 ++fmt;
434 } else if (*fmt == 'I' && *(fmt+1) == '6' && *(fmt+2) == '4') {
435 qualifier = *fmt;
436 fmt += 3;
437 } else if (*fmt == 'I' && *(fmt+1) == '3' && *(fmt+2) == '2') {
438 qualifier = 'l';
439 fmt += 3;
440 } else if (*fmt == 'F' && *(fmt+1) == 'p') {
441 fmt += 1;
442 flags |= REMOVEHEX;
443 }
444
445 /* default base */
446 base = 10;
447
448 switch (*fmt) {
449 case 'c': /* finished */
450 if (qualifier == 'l' || qualifier == 'w') {
451 wchar_t sw1[2];
452 /* print unicode string */
453 sw1[0] = (wchar_t) va_arg(args, int);
454 sw1[1] = 0;
455 str = stringw(str, end, (wchar_t *)&sw1, -1, field_width, precision, flags);
456 } else {
457 char s1[2];
458 /* print ascii string */
459 s1[0] = ( unsigned char) va_arg(args, int);
460 s1[1] = 0;
461 str = string(str, end, (char *)&s1, -1, field_width, precision, flags);
462 }
463 continue;
464
465 case 'C': /* finished */
466 if (!(flags & LEFT))
467 while (--field_width > 0) {
468 if (str <= end)
469 *str = ' ';
470 ++str;
471 }
472 if (qualifier == 'h') {
473 if (str <= end)
474 *str = (unsigned char) va_arg(args, int);
475 ++str;
476 } else {
477 if (str <= end)
478 *str = (unsigned char)(wchar_t) va_arg(args, int);
479 ++str;
480 }
481 while (--field_width > 0) {
482 if (str <= end)
483 *str = ' ';
484 ++str;
485 }
486 continue;
487
488 case 's': /* finished */
489 if (qualifier == 'l' || qualifier == 'w') {
490 /* print unicode string */
491 sw = va_arg(args, wchar_t *);
492 str = stringw(str, end, sw, -1, field_width, precision, flags);
493 } else {
494 /* print ascii string */
495 s = va_arg(args, char *);
496 str = string(str, end, s, -1, field_width, precision, flags);
497 }
498 continue;
499
500 case 'S':
501 if (qualifier == 'h') {
502 /* print ascii string */
503 s = va_arg(args, char *);
504 str = string(str, end, s, -1, field_width, precision, flags);
505 } else {
506 /* print unicode string */
507 sw = va_arg(args, wchar_t *);
508 str = stringw(str, end, sw, -1, field_width, precision, flags);
509 }
510 continue;
511
512 case 'Z':
513 if (qualifier == 'w') {
514 /* print counted unicode string */
515 PUNICODE_STRING pus = va_arg(args, PUNICODE_STRING);
516 if ((pus == NULL) || (pus->Buffer == NULL)) {
517 sw = NULL;
518 len = -1;
519 } else {
520 sw = pus->Buffer;
521 len = pus->Length / sizeof(WCHAR);
522 }
523 str = stringw(str, end, sw, len, field_width, precision, flags);
524 } else {
525 /* print counted ascii string */
526 PANSI_STRING pus = va_arg(args, PANSI_STRING);
527 if ((pus == NULL) || (pus->Buffer == NULL)) {
528 s = NULL;
529 len = -1;
530 } else {
531 s = pus->Buffer;
532 len = pus->Length;
533 }
534 str = string(str, end, s, len, field_width, precision, flags);
535 }
536 continue;
537
538 case 'p':
539 if ((flags & LARGE) == 0)
540 flags |= LARGE;
541
542 if (field_width == -1) {
543 field_width = 2 * sizeof(void *);
544 flags |= ZEROPAD;
545 }
546 str = number(str, end,
547 (unsigned long) va_arg(args, void *), 16,
548 field_width, precision, flags);
549 continue;
550
551 case 'n':
552 /* FIXME: What does C99 say about the overflow case here? */
553 if (qualifier == 'l') {
554 long * ip = va_arg(args, long *);
555 *ip = (str - buf);
556 } else {
557 int * ip = va_arg(args, int *);
558 *ip = (str - buf);
559 }
560 continue;
561
562 /* float number formats - set up the flags and "break" */
563 case 'e':
564 case 'E':
565 case 'f':
566 case 'g':
567 case 'G':
568 _double = (double)va_arg(args, double);
569 if ( _isnan(_double) ) {
570 s = "Nan";
571 len = 3;
572 while ( len > 0 ) {
573 if (str <= end)
574 *str = *s++;
575 ++str;
576 len --;
577 }
578 } else if ( _isinf(_double) < 0 ) {
579 s = "-Inf";
580 len = 4;
581 while ( len > 0 ) {
582 if (str <= end)
583 *str = *s++;
584 ++str;
585 len --;
586 }
587 } else if ( _isinf(_double) > 0 ) {
588 s = "+Inf";
589 len = 4;
590 while ( len > 0 ) {
591 if (str <= end)
592 *str = *s++;
593 ++str;
594 len --;
595 }
596 } else {
597 if ( precision == -1 )
598 precision = 6;
599 str = numberf(str, end, (int)_double, base, field_width, precision, flags);
600 }
601
602 continue;
603
604
605 /* integer number formats - set up the flags and "break" */
606 case 'o':
607 base = 8;
608 break;
609
610 case 'b':
611 base = 2;
612 break;
613
614 case 'X':
615 flags |= LARGE;
616 case 'x':
617 base = 16;
618 break;
619
620 case 'd':
621 case 'i':
622 flags |= SIGN;
623 case 'u':
624 break;
625
626 default:
627 if (*fmt) {
628 if (str <= end)
629 *str = *fmt;
630 ++str;
631 } else
632 --fmt;
633 continue;
634 }
635
636 if (qualifier == 'I')
637 num = va_arg(args, unsigned long long);
638 else if (qualifier == 'l') {
639 if (flags & SIGN)
640 num = va_arg(args, long);
641 else
642 num = va_arg(args, unsigned long);
643 }
644 else if (qualifier == 'h') {
645 if (flags & SIGN)
646 num = va_arg(args, int);
647 else
648 num = va_arg(args, unsigned int);
649 }
650 else {
651 if (flags & SIGN)
652 num = va_arg(args, int);
653 else
654 num = va_arg(args, unsigned int);
655 }
656 str = number(str, end, num, base, field_width, precision, flags);
657 }
658 if (str <= end)
659 *str = '\0';
660 else if (cnt > 0)
661 /* don't write out a null byte if the buf size is zero */
662 *end = '\0';
663 return str-buf;
664 }
665
666
667 /*
668 * @implemented
669 */
670 int lnx_sprintf(char * buf, const char *fmt, ...)
671 {
672 va_list args;
673 int i;
674
675 va_start(args, fmt);
676 i=lnx_vsnprintf(buf,MAXLONG,fmt,args);
677 va_end(args);
678 return i;
679 }
680
681 #if 0
682 /*
683 * @implemented
684 */
685 int _snprintf(char * buf, size_t cnt, const char *fmt, ...)
686 {
687 va_list args;
688 int i;
689
690 va_start(args, fmt);
691 i=_vsnprintf(buf,cnt,fmt,args);
692 va_end(args);
693 return i;
694 }
695
696
697 /*
698 * @implemented
699 */
700 int __cdecl vsprintf(char *buf, const char *fmt, va_list args)
701 {
702 return _vsnprintf(buf,MAXLONG,fmt,args);
703 }
704 #endif
705 /* EOF */