root / Whitix / branches / hybrid / lib / vsprintf.c

Revision 545, 5.1 kB (checked in by mwhitworth, 3 months ago)

Add some SYMBOL_EXPORT functions.

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/* Finally I've got round to coding a industry-strength vsprintf, although some ideas are from Linux.
20There aren't a thousands ways to code a vsprintf y'know.Phew, coded this all quickly. Should be very useful */
21
22/* TODO: Edit this to make it cleaner */
23
24#include <init.h>
25#include <module.h>
26#include <string.h>
27#include <typedefs.h>
28
29#define SIGN 1
30#define ZEROPAD 2
31#define PLUS 4
32#define SPACE 8
33#define LEFT 16
34#define SPECIAL 32
35#define SMALL 64
36
37#define is_digit(c) ((c) >= '0' && (c) <= '9')
38#define do_div(n,base) ({ \
39int __res; \
40__asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \
41__res; })
42
43int skip_atoi(const char** s)
44{
45        int i=0;
46        while (is_digit(**s))
47                i=i*10+*((*s)++)-'0';
48        return i;
49}
50
51char* number(char* str,int num,int base,int size,int precision,int type)
52{
53        char c,sign,tmp[36];
54        const char* digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
55        int i=0;
56       
57        if (type & SMALL) digits="0123456789abcdefghijklmnopqrstuvwxyz";
58        if (type & LEFT) type &= ~ZEROPAD;
59        if (base < 2 || base > 36)
60                return NULL;
61        c=(type & ZEROPAD) ? '0' : ' ';
62        if (type & SIGN && num < 0)
63        {
64                sign='-';
65                num=-num;
66        }else
67                sign=(type & PLUS) ? '+' : ((type & SPACE) ? ' ' : 0);
68        if (sign) size--;
69        if (type & SPECIAL)
70        {
71                if (base == 16) size-=2;
72                else if (base == 8) size--;
73        }
74               
75        if (num == 0)
76                tmp[i++]='0';
77        else while (num != 0)
78        {
79                tmp[i++]=digits[do_div(num,base)];
80        }
81
82        if (i>precision) precision=i;
83        size-=precision;
84        if (!(type & (ZEROPAD+LEFT)))
85                while (size-- > 0)
86                        *str++=' ';
87                       
88        if (sign)
89                *str++=sign;
90       
91        if (type & SPECIAL)
92        {
93                if (base == 8)
94                        *str++='0';
95                else if (base == 16)
96                {
97                        *str++='0';
98                        *str++=digits[33];
99                }
100        }
101               
102        if (!(type & LEFT))
103                while (size-- > 0)
104                        *str++=c;
105                       
106        while (i < precision--)
107                *str++='0';
108        while (i-- > 0)
109                *str++=tmp[i];
110        while (size-- > 0)
111                *str++=' ';
112        return str;
113}
114
115int vsprintf(char* buf,const char* fmt,va_list args)
116{
117        char* str=buf;
118        int fieldWidth,precision,qualifier,flags;
119
120        for (; *fmt; fmt++)
121        {
122                fieldWidth=precision=qualifier=-1;
123                flags=0;
124
125                if (LIKELY(*fmt != '%'))
126                {
127                        *str++=*fmt;
128                        continue;
129                }
130               
131                repeat:
132                ++fmt;
133                switch (*fmt)
134                {
135                        case '-': flags |= LEFT; goto repeat;
136                        case '+': flags |= PLUS; goto repeat;
137                        case ' ': flags |= SPACE; goto repeat;
138                        case '#': flags |= SPECIAL; goto repeat;
139                        case '0': flags |= ZEROPAD; goto repeat;
140                }
141               
142                /* Deal with the field width */
143                if (is_digit(*fmt))
144                        fieldWidth=skip_atoi(&fmt);
145                else if (*fmt == '*')
146                {
147                        fieldWidth=va_arg(args,int);
148                        if (fieldWidth < 0)
149                        {
150                                fieldWidth=-fieldWidth;
151                                flags |= LEFT;
152                        }
153                }
154               
155                if (*fmt == '.')
156                {
157                        ++fmt;
158                        if (is_digit(*fmt))
159                                precision=skip_atoi(&fmt);
160                        else if (*fmt == '*')
161                        {
162                                precision=va_arg(args,int);
163                        }
164                        if (precision < 0)
165                                precision=0;
166                }
167               
168                qualifier=-1;
169                if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L')
170                {
171                        qualifier=*fmt;
172                        ++fmt;
173                }
174               
175                switch (*fmt)
176                {
177                case 'c':
178                        if (!(flags & LEFT))
179                                while (--fieldWidth > 0)
180                                        *str++=' ';
181                        *str++=(unsigned char)va_arg(args,int);
182                        while (--fieldWidth > 0)
183                                *str++=' ';                     
184                        break;
185
186                case 's':
187                {
188                        char* s=va_arg(args,char*);
189                        if (!s)
190                                s="<NULL>";
191                        int len=strlen(s);
192                        if (precision < 0)
193                                precision=len;
194                        else if (len > precision)
195                                len=precision;
196                               
197                        if (!(flags & LEFT))
198                                while (len < fieldWidth--)
199                                        *str++=' ';
200                        int i;
201                        for (i=0; i<len; i++)
202                                *str++=*s++;
203                               
204                        while (len < fieldWidth--)
205                                *str++=' ';
206                        break;
207                }
208               
209                case 'o':
210                        str=number(str,va_arg(args,unsigned long),8,fieldWidth,
211                                precision,flags);
212                        break;
213                       
214                case 'p':
215                        if (fieldWidth == -1)
216                        {
217                                fieldWidth=8;
218                                flags |= ZEROPAD;
219                        }
220                        str=number(str,(unsigned long)va_arg(args,void*),16,fieldWidth,
221                                precision,flags);
222                        break;
223                       
224                case 'x':
225                        flags |= SMALL;
226                case 'X':
227                        str=number(str,va_arg(args,unsigned long),16,fieldWidth,
228                                precision,flags);
229                        break;
230                case 'd':
231                case 'i':
232                        flags |= SIGN;
233                case 'u':
234                        str=number(str,va_arg(args,unsigned long),10,fieldWidth,
235                                precision,flags);
236                        break;
237                default:
238                        if (*fmt != '%')
239                                *str++ = '%';
240                        if (*fmt)
241                                *str++ = *fmt;
242                        else
243                                --fmt;
244                        break;
245                }
246        }
247        *str='\0';
248        return (str-buf);
249}
250
251SYMBOL_EXPORT(vsprintf);
252
253int sprintf(char* buf,const char* fmt,...)
254{
255        int i;
256        va_list args;
257
258        va_start(args,fmt);
259        i=vsprintf(buf,fmt,args);
260        va_end(args);
261        return i;
262}
263
264SYMBOL_EXPORT(sprintf);
Note: See TracBrowser for help on using the browser.