root/Whitix/trunk/lib/vsprintf.c

Revision 1935, 6.8 KB (checked in by mwhitworth, 3 years ago)

Add sprintf stub.

Line 
1/*  This file is part of Whitix.
2 *
3 *  Whitix is free software; you can redistribute it and/or modify
4 *  it under the terms of the GNU General Public License as published by
5 *  the Free Software Foundation; either version 2 of the License, or
6 *  (at your option) any later version.
7 *
8 *  Whitix is distributed in the hope that it will be useful,
9 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 *  GNU General Public License for more details.
12 *
13 *  You should have received a copy of the GNU General Public License
14 *  along with Whitix; if not, write to the Free Software
15 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
16 *
17 */
18
19/* TODO: Edit this to make it cleaner */
20
21#include <module.h>
22#include <string.h>
23#include <typedefs.h>
24#include <malloc.h>
25#include <types.h>
26
27#define SIGN 1
28#define ZEROPAD 2
29#define PLUS 4
30#define SPACE 8
31#define LEFT 16
32#define SPECIAL 32
33#define SMALL 64
34
35#define is_digit(c) ((c) >= '0' && (c) <= '9')
36
37#define do_div(n,base) ({ \
38        unsigned long __upper, __low, __high, __mod, __base; \
39        __base = (base); \
40        asm("":"=a" (__low), "=d" (__high):"A" (n)); \
41        __upper = __high; \
42        if (__high) { \
43                __upper = __high % (__base); \
44                __high = __high / (__base); \
45        } \
46        asm("divl %2":"=a" (__low), "=d" (__mod):"rm" (__base), "0" (__low), "1" (__upper)); \
47        asm("":"=A" (n):"a" (__low),"d" (__high)); \
48        __mod; \
49})
50
51int skip_atoi(const char** s)
52{
53        int i=0;
54        while (is_digit(**s))
55                i=i*10+*((*s)++)-'0';
56        return i;
57}
58
59char* number(char* str, char* end, unsigned long long num,int base,int size,int precision,int type)
60{
61        char c,sign,tmp[36];
62        const char* digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
63        int i=0;
64       
65        if (type & SMALL) digits="0123456789abcdefghijklmnopqrstuvwxyz";
66        if (type & LEFT) type &= ~ZEROPAD;
67       
68        if (base < 2 || base > 36)
69                return NULL;
70               
71        c=(type & ZEROPAD) ? '0' : ' ';
72       
73        if (type & SIGN && (signed long long)num < 0)
74        {
75                sign='-';
76                num= -(signed long long)num;
77        }else
78                sign=(type & PLUS) ? '+' : ((type & SPACE) ? ' ' : 0);
79               
80        if (sign)
81                size--;
82       
83        if (type & SPECIAL)
84        {
85                if (base == 16) size-=2;
86                else if (base == 8) size--;
87        }
88               
89        if (num == 0)
90                tmp[i++]='0';
91        else while (num != 0)
92        {
93                tmp[i++]=digits[do_div(num,base)];
94        }
95
96        if (i>precision)
97                precision=i;
98               
99        size-=precision;
100       
101        if (!(type & (ZEROPAD+LEFT)))
102                while (size-- > 0)
103                {
104                        if (str < end)
105                                *str = ' ';
106                        str++;
107                }
108                       
109        if (sign)
110        {
111                if (str < end)
112                        *str = sign;
113               
114                str++;
115        }
116       
117        if (type & SPECIAL && str < end)
118        {
119                if (base == 8)
120                {
121                        if (str < end)
122                                *str = '0';
123                        str++;
124                }else if (base == 16)
125                {
126                        if (str < end)
127                                *str='0';
128                        str++;
129                       
130                        if (str < end)
131                                *str = digits[33];
132                               
133                        str++;
134                }
135        }
136               
137        if (!(type & LEFT))
138                while (size-- > 0)
139                {
140                        if (str < end)
141                                *str = c;
142                        str++;
143                }
144                       
145        while (i < precision--)
146        {
147                if (str < end)
148                        *str='0';
149                       
150                str++;
151        }
152       
153        while (i-- > 0)
154        {
155                if (str < end)
156                        *str = tmp[i];
157               
158                str++;
159        }
160       
161        while (size-- > 0)
162        {
163                if (str < end)
164                        *str = ' ';
165                       
166                str++;
167        }
168               
169        return str;
170}
171
172int vsnprintf(char* buf, int size, const char* fmt, VaList args)
173{
174        char* str=buf;
175        char* end;
176        int fieldWidth,precision,qualifier,flags;
177
178        end = buf+size;
179       
180        if (end < buf)
181        {
182                end = ((void*)-1);
183                size = end - buf;
184        }
185
186        for (; *fmt; fmt++)
187        {
188                fieldWidth=precision=qualifier=-1;
189                flags=0;
190
191                if (LIKELY(*fmt != '%'))
192                {
193                        if (str < end)
194                                *str = *fmt;
195                               
196                        str++;
197                        continue;
198                }
199               
200                repeat:
201                ++fmt;
202                switch (*fmt)
203                {
204                        case '-': flags |= LEFT; goto repeat;
205                        case '+': flags |= PLUS; goto repeat;
206                        case ' ': flags |= SPACE; goto repeat;
207                        case '#': flags |= SPECIAL; goto repeat;
208                        case '0': flags |= ZEROPAD; goto repeat;
209                }
210               
211                /* Deal with the field width */
212                if (is_digit(*fmt))
213                        fieldWidth=skip_atoi(&fmt);
214                else if (*fmt == '*')
215                {
216                        fieldWidth=VaArg(args, int);
217                        if (fieldWidth < 0)
218                        {
219                                fieldWidth=-fieldWidth;
220                                flags |= LEFT;
221                        }
222                }
223               
224                if (*fmt == '.')
225                {
226                        ++fmt;
227                        if (is_digit(*fmt))
228                                precision=skip_atoi(&fmt);
229                        else if (*fmt == '*')
230                        {
231                                precision=VaArg(args,int);
232                        }
233                        if (precision < 0)
234                                precision=0;
235                }
236               
237                qualifier=-1;
238                if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L')
239                {
240                        qualifier=*fmt;
241                        ++fmt;
242                }
243               
244                unsigned long long num=0;
245               
246                switch (*fmt)
247                {
248                case 'c':
249                        if (!(flags & LEFT))
250                                while (--fieldWidth > 0)
251                                {
252                                        if (str < end)
253                                                *str=' ';
254                                               
255                                        ++str;
256                                }
257                               
258                        if (str < end)
259                                *str=(unsigned char)VaArg(args,int);
260                               
261                        str++;
262                               
263                        while (--fieldWidth > 0)
264                        {
265                                if (str < end)
266                                        *str=' ';
267                                       
268                                str++;
269                        }               
270                        break;
271
272                case 's':
273                {
274                        char* s=VaArg(args,char*);
275                        if (!s)
276                                s="<NULL>";
277                        int len=strlen(s);
278                        if (precision < 0)
279                                precision=len;
280                        else if (len > precision)
281                                len=precision;
282                               
283                        if (!(flags & LEFT))
284                                while (len < fieldWidth--)
285                                {
286                                        if (str < end)
287                                                *str=' ';
288                                               
289                                        str++;
290                                }
291                        int i;
292                        for (i=0; i<len; i++)
293                        {
294                                if (str < end)
295                                        *str=*s;
296                                       
297                                str++;
298                                s++;
299                        }
300                               
301                        while (len < fieldWidth--)
302                        {
303                                if (str < end)                 
304                                        *str++=' ';
305                        }
306                        break;
307                }
308               
309                case 'o':
310                        str=number(str, end, VaArg(args,unsigned long),8,fieldWidth,
311                                precision,flags);
312                        break;
313                       
314                case 'p':
315                        if (fieldWidth == -1)
316                        {
317                                fieldWidth=8;
318                                flags |= ZEROPAD;
319                        }
320                        str=number(str, end, (unsigned long)VaArg(args,void*),16,fieldWidth,
321                                precision,flags);
322                        break;
323                       
324                case 'x':
325                        flags |= SMALL;
326                case 'X':
327                        str=number(str, end, VaArg(args,unsigned long),16,fieldWidth,
328                                precision,flags);
329                        break;
330                case 'd':
331                case 'i':
332                        flags |= SIGN;
333                case 'u':
334                        num = VaArg(args, unsigned int);
335                        if (flags & SIGN)
336                                num = (signed int)num;
337                        str=number(str, end, num, 10, fieldWidth, precision,flags);
338                        break;
339                default:
340                        if (str < end)
341                                *str = '%';
342                       
343                        if (*fmt)
344                        {
345                                if (str < end)
346                                        *str = *fmt;
347                                ++str;
348                        }else
349                                --fmt;
350                        break;
351                }
352        }
353       
354        if (size > 0)
355        {
356                if (str < end)
357                        *str = '\0';
358                else
359                        end[-1] = '\0';
360        }
361       
362        return (str-buf);
363}
364
365SYMBOL_EXPORT(vsnprintf);
366
367int vsprintf(char* buf,const char* fmt, VaList args)
368{
369        return vsnprintf(buf, INT_MAX, fmt, args);
370}
371
372SYMBOL_EXPORT(vsprintf);
373
374int snprintf(char* buf, unsigned int size, const char* fmt, ...)
375{
376        int ret;
377        VaList args;
378
379        VaStart(args, fmt);
380        ret = vsnprintf(buf, size, fmt, args);
381        VaEnd(args);
382
383        return ret;
384}
385
386SYMBOL_EXPORT(snprintf);
387
388char* vasprintf(const char* fmt, VaList args)
389{
390        int length;
391        char* ret;
392        VaList temp;
393       
394        VaCopy(temp, args);
395       
396        length = vsnprintf(NULL, 0, fmt, temp);
397       
398        VaEnd(temp);
399       
400        ret = (char*)MemAlloc(length + 1);
401       
402        if (!ret)
403                return NULL;
404       
405        vsnprintf(ret, length+1, fmt, args);
406
407        return ret;
408}
409
410SYMBOL_EXPORT(vasprintf);
411
412/* sprintf, used by Linux drivers mostly. */
413int sprintf(char* str, const char* fmt, ...)
414{
415        KePrint("sprintf");
416        return 0;
417}
418
419SYMBOL_EXPORT(sprintf);
Note: See TracBrowser for help on using the browser.