## iof-bird-daemon / lib / printf.c @ 294c182e

History | View | Annotate | Download (6.5 KB)

1 | ecacdfa4 | Martin Mares | ```
/*
``` |
---|---|---|---|

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 | 53a416d3 | Martin Mares | ```
* Buffer size limitation implemented by Martin Mares.
``` |

8 | ecacdfa4 | Martin Mares | ```
*/
``` |

9 | |||

10 | #include "nest/bird.h" |
||

11 | #include "string.h" |
||

12 | |||

13 | d997534f | Martin Mares | #include <errno.h> |

14 | #include <string.h> |
||

15 | |||

16 | ecacdfa4 | Martin Mares | ```
/* 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 | 53a416d3 | Martin Mares | static char * number(char * str, long num, int base, int size, int precision, |

43 | int type, int remains) |
||

44 | ecacdfa4 | Martin Mares | { |

45 | char c,sign,tmp[66]; |
||

46 | const char *digits="0123456789abcdefghijklmnopqrstuvwxyz"; |
||

47 | ```
int i;
``` |
||

48 | |||

49 | 53a416d3 | Martin Mares | if (size >= 0 && (remains -= size) < 0) |

50 | return NULL; |
||

51 | ecacdfa4 | Martin Mares | ```
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 | 53a416d3 | Martin Mares | if (size < 0 && -size > remains) |

87 | return NULL; |
||

88 | ecacdfa4 | Martin Mares | ```
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 | 53a416d3 | Martin Mares | int bvsnprintf(char *buf, int size, const char *fmt, va_list args) |

114 | ecacdfa4 | Martin Mares | { |

115 | ```
int len;
``` |
||

116 | unsigned long num; |
||

117 | ```
int i, base;
``` |
||

118 | 53a416d3 | Martin Mares | ```
char *str, *start;
``` |

119 | ecacdfa4 | Martin Mares | 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 | 53a416d3 | Martin Mares | ```
for (start=str=buf ; *fmt ; ++fmt, size-=(str-start), start=str) {
``` |

129 | ecacdfa4 | Martin Mares | if (*fmt != '%') { |

130 | 53a416d3 | Martin Mares | ```
if (!size)
``` |

131 | return -1; |
||

132 | ecacdfa4 | Martin Mares | *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 | 53a416d3 | Martin Mares | ```
if (field_width > size)
``` |

188 | return -1; |
||

189 | ecacdfa4 | Martin Mares | ```
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 | d997534f | Martin Mares | case 'm': |

200 | s = strerror(errno); |
||

201 | ```
goto str;
``` |
||

202 | ecacdfa4 | Martin Mares | case 's': |

203 | ```
s = va_arg(args, char *);
``` |
||

204 | ```
if (!s)
``` |
||

205 | ```
s = "<NULL>";
``` |
||

206 | |||

207 | d997534f | Martin Mares | ```
str:
``` |

208 | ecacdfa4 | Martin Mares | len = strlen(s); |

209 | if (precision >= 0 && len > precision) |
||

210 | len = precision; |
||

211 | 53a416d3 | Martin Mares | ```
if (len > size)
``` |

212 | return -1; |
||

213 | ecacdfa4 | Martin Mares | |

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 | 53a416d3 | Martin Mares | field_width, precision, flags, size); |

231 | ```
if (!str)
``` |
||

232 | return -1; |
||

233 | ecacdfa4 | Martin Mares | ```
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 | 53a416d3 | Martin Mares | ```
if (size < STD_ADDRESS_P_LENGTH)
``` |

249 | return -1; |
||

250 | ecacdfa4 | Martin Mares | ```
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 | 53a416d3 | Martin Mares | if (size < 2) |

280 | return -1; |
||

281 | ecacdfa4 | Martin Mares | 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 | 4254dc45 | Martin Mares | num = (unsigned short) va_arg(args, int); |

293 | ecacdfa4 | Martin Mares | ```
if (flags & SIGN)
``` |

294 | 4254dc45 | Martin Mares | ```
num = (short) num;
``` |

295 | ecacdfa4 | Martin Mares | } else if (flags & SIGN) |

296 | ```
num = va_arg(args, int);
``` |
||

297 | ```
else
``` |
||

298 | num = va_arg(args, unsigned int); |
||

299 | 53a416d3 | Martin Mares | str = number(str, num, base, field_width, precision, flags, size); |

300 | ```
if (!str)
``` |
||

301 | return -1; |
||

302 | ecacdfa4 | Martin Mares | } |

303 | 53a416d3 | Martin Mares | ```
if (!size)
``` |

304 | return -1; |
||

305 | ecacdfa4 | Martin Mares | ```
*str = '\0';
``` |

306 | ```
return str-buf;
``` |
||

307 | } |
||

308 | |||

309 | 53a416d3 | Martin Mares | int bvsprintf(char *buf, const char *fmt, va_list args) |

310 | { |
||

311 | return bvsnprintf(buf, 1000000000, fmt, args); |
||

312 | } |
||

313 | |||

314 | ecacdfa4 | Martin Mares | int bsprintf(char * buf, const char *fmt, ...) |

315 | { |
||

316 | 53a416d3 | Martin Mares | va_list args; |

317 | ```
int i;
``` |
||

318 | ecacdfa4 | Martin Mares | |

319 | 53a416d3 | Martin Mares | va_start(args, fmt); |

320 | ```
i=bvsnprintf(buf, 1000000000, fmt, args);
``` |
||

321 | va_end(args); |
||

322 | ```
return i;
``` |
||

323 | } |
||

324 | |||

325 | int bsnprintf(char * buf, int size, const char *fmt, ...) |
||

326 | { |
||

327 | va_list args; |
||

328 | ```
int i;
``` |
||

329 | |||

330 | va_start(args, fmt); |
||

331 | i=bvsnprintf(buf, size, fmt, args); |
||

332 | va_end(args); |
||

333 | ```
return i;
``` |
||

334 | ecacdfa4 | Martin Mares | } |