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