UbixOS V2 2.0

vsprintf.c
Go to the documentation of this file.
1 /*-
2 * Copyright (c) 2002-2018 The UbixOS Project.
3 * All rights reserved.
4 *
5 * This was developed by Christopher W. Olsen for the UbixOS Project.
6 *
7 * Redistribution and use in source and binary forms, with or without modification, are permitted
8 * provided that the following conditions are met:
9 *
10 * 1) Redistributions of source code must retain the above copyright notice, this list of
11 * conditions, the following disclaimer and the list of authors.
12 * 2) Redistributions in binary form must reproduce the above copyright notice, this list of
13 * conditions, the following disclaimer and the list of authors in the documentation and/or
14 * other materials provided with the distribution.
15 * 3) Neither the name of the UbixOS Project nor the names of its contributors may be used to
16 * endorse or promote products derived from this software without specific prior written
17 * permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
20 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
22 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
24 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
30 /*
31 * Wirzenius wrote this portably, Torvalds fucked it up :-)
32 */
33
34 #include <stdarg.h>
35 #include <string.h>
36
37 /* we use this so that we can do without the ctype library */
38 #define is_digit(c) ((c) >= '0' && (c) <= '9')
39
40 static int skip_atoi(const char **s) {
41 int i = 0;
42
43 while (is_digit(**s))
44 i = i * 10 + *((*s)++) - '0';
45 return i;
46 }
47
48 #define ZEROPAD 1 /* pad with zero */
49 #define SIGN 2 /* unsigned/signed long */
50 #define PLUS 4 /* show plus */
51 #define SPACE 8 /* space if plus */
52 #define LEFT 16 /* left justified */
53 #define SPECIAL 32 /* 0x */
54 #define SMALL 64 /* use 'abcdef' instead of 'ABCDEF' */
55
56 #define do_div(n,base) ({ \
57 int __res; \
58 __asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \
59 __res; })
60
61 static char * number(char * str, int num, int base, int size, int precision, int type) {
62 char c, sign, tmp[36];
63 const char *digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
64 int i;
65
66 if (type & SMALL)
67 digits = "0123456789abcdefghijklmnopqrstuvwxyz";
68 if (type & LEFT)
69 type &= ~ZEROPAD;
70 if (base < 2 || base > 36)
71 return 0;
72 c = (type & ZEROPAD) ? '0' : ' ';
73 if ((type & SIGN) && num < 0) {
74 sign = '-';
75 num = -num;
76 }
77 else
78 sign = (type & PLUS) ? '+' : ((type & SPACE) ? ' ' : 0);
79 if (sign)
80 size--;
81 if (type & SPECIAL) {
82 if (base == 16) {
83 size -= 2;
84 }
85 else if (base == 8) {
86 size--;
87 }
88 }
89 i = 0;
90 if (num == 0)
91 tmp[i++] = '0';
92 else
93 while (num != 0)
94 tmp[i++] = digits[do_div(num, base)];
95 if (i > precision)
96 precision = i;
97 size -= precision;
98 if (!(type & (ZEROPAD + LEFT)))
99 while (size-- > 0)
100 *str++ = ' ';
101 if (sign)
102 *str++ = sign;
103 if (type & SPECIAL) {
104 if (base == 8) {
105 *str++ = '0';
106 }
107 else if (base == 16) {
108 *str++ = '0';
109 *str++ = digits[33];
110 }
111 }
112 if (!(type & LEFT))
113 while (size-- > 0)
114 *str++ = c;
115 while (i < precision--)
116 *str++ = '0';
117 while (i-- > 0)
118 *str++ = tmp[i];
119 while (size-- > 0)
120 *str++ = ' ';
121 return str;
122 }
123
124 int vsprintf(char *buf, const char *fmt, va_list args) {
125 int len;
126 int i;
127 char * str;
128 char *s;
129 int *ip;
130
131 int flags; /* flags to number() */
132
133 int field_width; /* width of output field */
134 int precision; /* min. # of digits for integers; max
135 number of chars for from string */
136 int qualifier; /* 'h', 'l', or 'L' for integer fields */
137
138 for (str = buf; *fmt; ++fmt) {
139 if (*fmt != '%') {
140 *str++ = *fmt;
141 continue;
142 }
143
144 /* process flags */
145 flags = 0;
146 repeat: ++fmt; /* this also skips first '%' */
147 switch (*fmt) {
148 case '-':
149 flags |= LEFT;
150 goto repeat;
151 case '+':
152 flags |= PLUS;
153 goto repeat;
154 case ' ':
155 flags |= SPACE;
156 goto repeat;
157 case '#':
158 flags |= SPECIAL;
159 goto repeat;
160 case '0':
161 flags |= ZEROPAD;
162 goto repeat;
163 }
164
165 /* get field width */
166 field_width = -1;
167 if (is_digit(*fmt))
168 field_width = skip_atoi(&fmt);
169 else if (*fmt == '*') {
170 /* it's the next argument */
171 field_width = va_arg(args, int);
172 if (field_width < 0) {
173 field_width = -field_width;
174 flags |= LEFT;
175 }
176 }
177
178 /* get the precision */
179 precision = -1;
180 if (*fmt == '.') {
181 ++fmt;
182 if (is_digit(*fmt))
183 precision = skip_atoi(&fmt);
184 else if (*fmt == '*') {
185 /* it's the next argument */
186 precision = va_arg(args, int);
187 }
188 if (precision < 0)
189 precision = 0;
190 }
191
192 /* get the conversion qualifier */
193 qualifier = -1;
194 if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') {
195 qualifier = *fmt;
196 ++fmt;
197 }
198
199 switch (*fmt) {
200 case 'c':
201 if (!(flags & LEFT))
202 while (--field_width > 0)
203 *str++ = ' ';
204 *str++ = (unsigned char) va_arg(args, int);
205 while (--field_width > 0)
206 *str++ = ' ';
207 break;
208
209 case 's':
210 s = va_arg(args, char *);
211 len = strlen(s);
212 if (precision < 0)
213 precision = len;
214 else if (len > precision)
215 len = precision;
216
217 if (!(flags & LEFT))
218 while (len < field_width--)
219 *str++ = ' ';
220 for (i = 0; i < len; ++i)
221 *str++ = *s++;
222 while (len < field_width--)
223 *str++ = ' ';
224 break;
225
226 case 'o':
227 str = number(str, va_arg(args, unsigned long), 8, field_width, precision, flags);
228 break;
229
230 case 'p':
231 if (field_width == -1) {
232 field_width = 8;
233 flags |= ZEROPAD;
234 }
235 str = number(str, (unsigned long) va_arg(args, void *), 16, field_width, precision, flags);
236 break;
237
238 case 'x':
239 flags |= SMALL;
240 case 'X':
241 str = number(str, va_arg(args, unsigned long), 16, field_width, precision, flags);
242 break;
243
244 case 'd':
245 case 'i':
246 flags |= SIGN;
247 case 'u':
248 str = number(str, va_arg(args, unsigned long), 10, field_width, precision, flags);
249 break;
250
251 case 'n':
252 ip = va_arg(args, int *);
253 *ip = (str - buf);
254 break;
255
256 default:
257 if (*fmt != '%')
258 *str++ = '%';
259 if (*fmt)
260 *str++ = *fmt;
261 else
262 --fmt;
263 break;
264 }
265 }
266 *str = '\0';
267 return str - buf;
268 }
269
270 /***
271 END
272 ***/
273
LEFT
#define LEFT
Definition: vsprintf.c:52
SPECIAL
#define SPECIAL
Definition: vsprintf.c:53
string.h
is_digit
#define is_digit(c)
Definition: vsprintf.c:38
vsprintf
int vsprintf(char *buf, const char *fmt, va_list args)
Definition: vsprintf.c:124
strlen
int strlen(const char *str)
Definition: strlen.c:55
va_list
char * va_list
Definition: stdarg.h:32
SMALL
#define SMALL
Definition: vsprintf.c:54
do_div
#define do_div(n, base)
Definition: vsprintf.c:56
ZEROPAD
#define ZEROPAD
Definition: vsprintf.c:48
stdarg.h
buf
Definition: buf.h:35
SIGN
#define SIGN
Definition: vsprintf.c:49
PLUS
#define PLUS
Definition: vsprintf.c:50
va_arg
#define va_arg(ap, type)
Definition: stdarg.h:44
SPACE
#define SPACE
Definition: vsprintf.c:51