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