iofbirddaemon / lib / printf.c @ 53a416d3
History  View  Annotate  Download (6.52 KB)
1 
/*


2 
* BIRD Library  Formatted Output

3 
*

4 
* (c) 1991, 1992 Lars Wirzenius & Linus Torvalds

5 
*

6 
* Hacked up for BIRD by Martin Mares <mj@ucw.cz>

7 
* Buffer size limitation implemented by Martin Mares.

8 
*/

9  
10 
#include "nest/bird.h" 
11 
#include "string.h" 
12  
13 
#include <errno.h> 
14 
#include <string.h> 
15  
16 
/* we use this so that we can do without the ctype library */

17 
#define is_digit(c) ((c) >= '0' && (c) <= '9') 
18  
19 
static int skip_atoi(const char **s) 
20 
{ 
21 
int i=0; 
22  
23 
while (is_digit(**s))

24 
i = i*10 + *((*s)++)  '0'; 
25 
return i;

26 
} 
27  
28 
#define ZEROPAD 1 /* pad with zero */ 
29 
#define SIGN 2 /* unsigned/signed long */ 
30 
#define PLUS 4 /* show plus */ 
31 
#define SPACE 8 /* space if plus */ 
32 
#define LEFT 16 /* left justified */ 
33 
#define SPECIAL 32 /* 0x */ 
34 
#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */ 
35  
36 
#define do_div(n,base) ({ \

37 
int __res; \

38 
__res = ((unsigned long) n) % (unsigned) base; \ 
39 
n = ((unsigned long) n) / (unsigned) base; \ 
40 
__res; }) 
41  
42 
static char * number(char * str, long num, int base, int size, int precision, 
43 
int type, int remains) 
44 
{ 
45 
char c,sign,tmp[66]; 
46 
const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; 
47 
int i;

48  
49 
if (size >= 0 && (remains = size) < 0) 
50 
return NULL; 
51 
if (type & LARGE)

52 
digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";

53 
if (type & LEFT)

54 
type &= ~ZEROPAD; 
55 
if (base < 2  base > 36) 
56 
return 0; 
57 
c = (type & ZEROPAD) ? '0' : ' '; 
58 
sign = 0;

59 
if (type & SIGN) {

60 
if (num < 0) { 
61 
sign = '';

62 
num = num; 
63 
size; 
64 
} else if (type & PLUS) { 
65 
sign = '+';

66 
size; 
67 
} else if (type & SPACE) { 
68 
sign = ' ';

69 
size; 
70 
} 
71 
} 
72 
if (type & SPECIAL) {

73 
if (base == 16) 
74 
size = 2;

75 
else if (base == 8) 
76 
size; 
77 
} 
78 
i = 0;

79 
if (num == 0) 
80 
tmp[i++]='0';

81 
else while (num != 0) 
82 
tmp[i++] = digits[do_div(num,base)]; 
83 
if (i > precision)

84 
precision = i; 
85 
size = precision; 
86 
if (size < 0 && size > remains) 
87 
return NULL; 
88 
if (!(type&(ZEROPAD+LEFT)))

89 
while(size>0) 
90 
*str++ = ' ';

91 
if (sign)

92 
*str++ = sign; 
93 
if (type & SPECIAL) {

94 
if (base==8) 
95 
*str++ = '0';

96 
else if (base==16) { 
97 
*str++ = '0';

98 
*str++ = digits[33];

99 
} 
100 
} 
101 
if (!(type & LEFT))

102 
while (size > 0) 
103 
*str++ = c; 
104 
while (i < precision)

105 
*str++ = '0';

106 
while (i > 0) 
107 
*str++ = tmp[i]; 
108 
while (size > 0) 
109 
*str++ = ' ';

110 
return str;

111 
} 
112  
113 
int bvsnprintf(char *buf, int size, const char *fmt, va_list args) 
114 
{ 
115 
int len;

116 
unsigned long num; 
117 
int i, base;

118 
char *str, *start;

119 
const char *s; 
120  
121 
int flags; /* flags to number() */ 
122  
123 
int field_width; /* width of output field */ 
124 
int precision; /* min. # of digits for integers; max 
125 
number of chars for from string */

126 
int qualifier; /* 'h', 'l', or 'L' for integer fields */ 
127  
128 
for (start=str=buf ; *fmt ; ++fmt, size=(strstart), start=str) {

129 
if (*fmt != '%') { 
130 
if (!size)

131 
return 1; 
132 
*str++ = *fmt; 
133 
continue;

134 
} 
135 

136 
/* process flags */

137 
flags = 0;

138 
repeat:

139 
++fmt; /* this also skips first '%' */

140 
switch (*fmt) {

141 
case '': flags = LEFT; goto repeat; 
142 
case '+': flags = PLUS; goto repeat; 
143 
case ' ': flags = SPACE; goto repeat; 
144 
case '#': flags = SPECIAL; goto repeat; 
145 
case '0': flags = ZEROPAD; goto repeat; 
146 
} 
147 

148 
/* get field width */

149 
field_width = 1;

150 
if (is_digit(*fmt))

151 
field_width = skip_atoi(&fmt); 
152 
else if (*fmt == '*') { 
153 
++fmt; 
154 
/* it's the next argument */

155 
field_width = va_arg(args, int);

156 
if (field_width < 0) { 
157 
field_width = field_width; 
158 
flags = LEFT; 
159 
} 
160 
} 
161  
162 
/* get the precision */

163 
precision = 1;

164 
if (*fmt == '.') { 
165 
++fmt; 
166 
if (is_digit(*fmt))

167 
precision = skip_atoi(&fmt); 
168 
else if (*fmt == '*') { 
169 
++fmt; 
170 
/* it's the next argument */

171 
precision = va_arg(args, int);

172 
} 
173 
if (precision < 0) 
174 
precision = 0;

175 
} 
176  
177 
/* get the conversion qualifier */

178 
qualifier = 1;

179 
if (*fmt == 'h'  *fmt == 'l'  *fmt == 'L') { 
180 
qualifier = *fmt; 
181 
++fmt; 
182 
} 
183  
184 
/* default base */

185 
base = 10;

186  
187 
if (field_width > size)

188 
return 1; 
189 
switch (*fmt) {

190 
case 'c': 
191 
if (!(flags & LEFT))

192 
while (field_width > 0) 
193 
*str++ = ' ';

194 
*str++ = (unsigned char) va_arg(args, int); 
195 
while (field_width > 0) 
196 
*str++ = ' ';

197 
continue;

198  
199 
case 'm': 
200 
s = strerror(errno); 
201 
goto str;

202 
case 's': 
203 
s = va_arg(args, char *);

204 
if (!s)

205 
s = "<NULL>";

206  
207 
str:

208 
len = strlen(s); 
209 
if (precision >= 0 && len > precision) 
210 
len = precision; 
211 
if (len > size)

212 
return 1; 
213  
214 
if (!(flags & LEFT))

215 
while (len < field_width)

216 
*str++ = ' ';

217 
for (i = 0; i < len; ++i) 
218 
*str++ = *s++; 
219 
while (len < field_width)

220 
*str++ = ' ';

221 
continue;

222  
223 
case 'p': 
224 
if (field_width == 1) { 
225 
field_width = 2*sizeof(void *); 
226 
flags = ZEROPAD; 
227 
} 
228 
str = number(str, 
229 
(unsigned long) va_arg(args, void *), 16, 
230 
field_width, precision, flags, size); 
231 
if (!str)

232 
return 1; 
233 
continue;

234  
235  
236 
case 'n': 
237 
if (qualifier == 'l') { 
238 
long * ip = va_arg(args, long *); 
239 
*ip = (str  buf); 
240 
} else {

241 
int * ip = va_arg(args, int *); 
242 
*ip = (str  buf); 
243 
} 
244 
continue;

245  
246 
/* IP address */

247 
case 'I': 
248 
if (size < STD_ADDRESS_P_LENGTH)

249 
return 1; 
250 
if (flags & SPECIAL)

251 
str = ip_ntox(va_arg(args, ip_addr), str); 
252 
else {

253 
len = ip_ntop(va_arg(args, ip_addr), str)  str; 
254 
str += len; 
255 
if (field_width >= 0) 
256 
while (len++ < STD_ADDRESS_P_LENGTH)

257 
*str++ = ' ';

258 
} 
259 
continue;

260  
261 
/* integer number formats  set up the flags and "break" */

262 
case 'o': 
263 
base = 8;

264 
break;

265  
266 
case 'X': 
267 
flags = LARGE; 
268 
case 'x': 
269 
base = 16;

270 
break;

271  
272 
case 'd': 
273 
case 'i': 
274 
flags = SIGN; 
275 
case 'u': 
276 
break;

277  
278 
default:

279 
if (size < 2) 
280 
return 1; 
281 
if (*fmt != '%') 
282 
*str++ = '%';

283 
if (*fmt)

284 
*str++ = *fmt; 
285 
else

286 
fmt; 
287 
continue;

288 
} 
289 
if (qualifier == 'l') 
290 
num = va_arg(args, unsigned long); 
291 
else if (qualifier == 'h') { 
292 
if (flags & SIGN)

293 
num = va_arg(args, short);

294 
else

295 
num = va_arg(args, unsigned short); 
296 
} else if (flags & SIGN) 
297 
num = va_arg(args, int);

298 
else

299 
num = va_arg(args, unsigned int); 
300 
str = number(str, num, base, field_width, precision, flags, size); 
301 
if (!str)

302 
return 1; 
303 
} 
304 
if (!size)

305 
return 1; 
306 
*str = '\0';

307 
return strbuf;

308 
} 
309  
310 
int bvsprintf(char *buf, const char *fmt, va_list args) 
311 
{ 
312 
return bvsnprintf(buf, 1000000000, fmt, args); 
313 
} 
314  
315 
int bsprintf(char * buf, const char *fmt, ...) 
316 
{ 
317 
va_list args; 
318 
int i;

319  
320 
va_start(args, fmt); 
321 
i=bvsnprintf(buf, 1000000000, fmt, args);

322 
va_end(args); 
323 
return i;

324 
} 
325  
326 
int bsnprintf(char * buf, int size, const char *fmt, ...) 
327 
{ 
328 
va_list args; 
329 
int i;

330  
331 
va_start(args, fmt); 
332 
i=bvsnprintf(buf, size, fmt, args); 
333 
va_end(args); 
334 
return i;

335 
} 