UbixOS  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