1 |
2a2d6309
|
(no author)
|
/*
|
2 |
|
|
* linux/lib/vsprintf.c
|
3 |
|
|
*
|
4 |
|
|
* Copyright (C) 1991, 1992 Linus Torvalds
|
5 |
|
|
*/
|
6 |
|
|
|
7 |
|
|
/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
|
8 |
|
|
/*
|
9 |
|
|
* Wirzenius wrote this portably, Torvalds fucked it up :-)
|
10 |
|
|
*/
|
11 |
|
|
|
12 |
|
|
/*
|
13 |
|
|
* Fri Jul 13 2001 Crutcher Dunnavant <crutcher+kernel@datastacks.com>
|
14 |
|
|
* - changed to provide snprintf and vsnprintf functions
|
15 |
|
|
* So Feb 1 16:51:32 CET 2004 Juergen Quade <quade@hsnr.de>
|
16 |
|
|
* - scnprintf and vscnprintf
|
17 |
|
|
*/
|
18 |
|
|
|
19 |
|
|
#include <stdarg.h>
|
20 |
ca1d468c
|
Holger Hans Peter Freyther
|
#include <limits.h>
|
21 |
2a2d6309
|
(no author)
|
#include <sys/types.h>
|
22 |
|
|
#include <string.h>
|
23 |
|
|
#include <asm/ctype.h>
|
24 |
|
|
|
25 |
|
|
#include <asm/div64.h>
|
26 |
|
|
|
27 |
|
|
/**
|
28 |
|
|
* simple_strtoul - convert a string to an unsigned long
|
29 |
|
|
* @cp: The start of the string
|
30 |
|
|
* @endp: A pointer to the end of the parsed string will be placed here
|
31 |
|
|
* @base: The number base to use
|
32 |
|
|
*/
|
33 |
|
|
unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base)
|
34 |
|
|
{
|
35 |
|
|
unsigned long result = 0,value;
|
36 |
|
|
|
37 |
|
|
if (!base) {
|
38 |
|
|
base = 10;
|
39 |
|
|
if (*cp == '0') {
|
40 |
|
|
base = 8;
|
41 |
|
|
cp++;
|
42 |
|
|
if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
|
43 |
|
|
cp++;
|
44 |
|
|
base = 16;
|
45 |
|
|
}
|
46 |
|
|
}
|
47 |
|
|
} else if (base == 16) {
|
48 |
|
|
if (cp[0] == '0' && toupper(cp[1]) == 'X')
|
49 |
|
|
cp += 2;
|
50 |
|
|
}
|
51 |
|
|
while (isxdigit(*cp) &&
|
52 |
|
|
(value = isdigit(*cp) ? *cp-'0' : toupper(*cp)-'A'+10) < base) {
|
53 |
|
|
result = result*base + value;
|
54 |
|
|
cp++;
|
55 |
|
|
}
|
56 |
|
|
if (endp)
|
57 |
|
|
*endp = (char *)cp;
|
58 |
|
|
return result;
|
59 |
|
|
}
|
60 |
|
|
|
61 |
|
|
|
62 |
|
|
/**
|
63 |
|
|
* simple_strtol - convert a string to a signed long
|
64 |
|
|
* @cp: The start of the string
|
65 |
|
|
* @endp: A pointer to the end of the parsed string will be placed here
|
66 |
|
|
* @base: The number base to use
|
67 |
|
|
*/
|
68 |
|
|
long simple_strtol(const char *cp,char **endp,unsigned int base)
|
69 |
|
|
{
|
70 |
|
|
if(*cp=='-')
|
71 |
|
|
return -simple_strtoul(cp+1,endp,base);
|
72 |
|
|
return simple_strtoul(cp,endp,base);
|
73 |
|
|
}
|
74 |
|
|
|
75 |
|
|
|
76 |
|
|
/**
|
77 |
|
|
* simple_strtoull - convert a string to an unsigned long long
|
78 |
|
|
* @cp: The start of the string
|
79 |
|
|
* @endp: A pointer to the end of the parsed string will be placed here
|
80 |
|
|
* @base: The number base to use
|
81 |
|
|
*/
|
82 |
|
|
unsigned long long simple_strtoull(const char *cp,char **endp,unsigned int base)
|
83 |
|
|
{
|
84 |
|
|
unsigned long long result = 0,value;
|
85 |
|
|
|
86 |
|
|
if (!base) {
|
87 |
|
|
base = 10;
|
88 |
|
|
if (*cp == '0') {
|
89 |
|
|
base = 8;
|
90 |
|
|
cp++;
|
91 |
|
|
if ((toupper(*cp) == 'X') && isxdigit(cp[1])) {
|
92 |
|
|
cp++;
|
93 |
|
|
base = 16;
|
94 |
|
|
}
|
95 |
|
|
}
|
96 |
|
|
} else if (base == 16) {
|
97 |
|
|
if (cp[0] == '0' && toupper(cp[1]) == 'X')
|
98 |
|
|
cp += 2;
|
99 |
|
|
}
|
100 |
|
|
while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp)
|
101 |
|
|
? toupper(*cp) : *cp)-'A'+10) < base) {
|
102 |
|
|
result = result*base + value;
|
103 |
|
|
cp++;
|
104 |
|
|
}
|
105 |
|
|
if (endp)
|
106 |
|
|
*endp = (char *)cp;
|
107 |
|
|
return result;
|
108 |
|
|
}
|
109 |
|
|
|
110 |
|
|
|
111 |
|
|
/**
|
112 |
|
|
* simple_strtoll - convert a string to a signed long long
|
113 |
|
|
* @cp: The start of the string
|
114 |
|
|
* @endp: A pointer to the end of the parsed string will be placed here
|
115 |
|
|
* @base: The number base to use
|
116 |
|
|
*/
|
117 |
|
|
long long simple_strtoll(const char *cp,char **endp,unsigned int base)
|
118 |
|
|
{
|
119 |
|
|
if(*cp=='-')
|
120 |
|
|
return -simple_strtoull(cp+1,endp,base);
|
121 |
|
|
return simple_strtoull(cp,endp,base);
|
122 |
|
|
}
|
123 |
|
|
|
124 |
|
|
static int skip_atoi(const char **s)
|
125 |
|
|
{
|
126 |
|
|
int i=0;
|
127 |
|
|
|
128 |
|
|
while (isdigit(**s))
|
129 |
|
|
i = i*10 + *((*s)++) - '0';
|
130 |
|
|
return i;
|
131 |
|
|
}
|
132 |
|
|
|
133 |
|
|
#define ZEROPAD 1 /* pad with zero */
|
134 |
|
|
#define SIGN 2 /* unsigned/signed long */
|
135 |
|
|
#define PLUS 4 /* show plus */
|
136 |
|
|
#define SPACE 8 /* space if plus */
|
137 |
|
|
#define LEFT 16 /* left justified */
|
138 |
|
|
#define SPECIAL 32 /* 0x */
|
139 |
|
|
#define LARGE 64 /* use 'ABCDEF' instead of 'abcdef' */
|
140 |
|
|
|
141 |
|
|
static char * number(char * buf, char * end, unsigned long long num, int base, int size, int precision, int type)
|
142 |
|
|
{
|
143 |
|
|
char c,sign,tmp[66];
|
144 |
|
|
const char *digits;
|
145 |
|
|
static const char small_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
146 |
|
|
static const char large_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
|
147 |
|
|
int i;
|
148 |
|
|
|
149 |
|
|
digits = (type & LARGE) ? large_digits : small_digits;
|
150 |
|
|
if (type & LEFT)
|
151 |
|
|
type &= ~ZEROPAD;
|
152 |
|
|
if (base < 2 || base > 36)
|
153 |
|
|
return NULL;
|
154 |
|
|
c = (type & ZEROPAD) ? '0' : ' ';
|
155 |
|
|
sign = 0;
|
156 |
|
|
if (type & SIGN) {
|
157 |
|
|
if ((signed long long) num < 0) {
|
158 |
|
|
sign = '-';
|
159 |
|
|
num = - (signed long long) num;
|
160 |
|
|
size--;
|
161 |
|
|
} else if (type & PLUS) {
|
162 |
|
|
sign = '+';
|
163 |
|
|
size--;
|
164 |
|
|
} else if (type & SPACE) {
|
165 |
|
|
sign = ' ';
|
166 |
|
|
size--;
|
167 |
|
|
}
|
168 |
|
|
}
|
169 |
|
|
if (type & SPECIAL) {
|
170 |
|
|
if (base == 16)
|
171 |
|
|
size -= 2;
|
172 |
|
|
else if (base == 8)
|
173 |
|
|
size--;
|
174 |
|
|
}
|
175 |
|
|
i = 0;
|
176 |
|
|
if (num == 0)
|
177 |
|
|
tmp[i++]='0';
|
178 |
|
|
else while (num != 0)
|
179 |
|
|
tmp[i++] = digits[do_div(num,base)];
|
180 |
|
|
if (i > precision)
|
181 |
|
|
precision = i;
|
182 |
|
|
size -= precision;
|
183 |
|
|
if (!(type&(ZEROPAD+LEFT))) {
|
184 |
|
|
while(size-->0) {
|
185 |
|
|
if (buf <= end)
|
186 |
|
|
*buf = ' ';
|
187 |
|
|
++buf;
|
188 |
|
|
}
|
189 |
|
|
}
|
190 |
|
|
if (sign) {
|
191 |
|
|
if (buf <= end)
|
192 |
|
|
*buf = sign;
|
193 |
|
|
++buf;
|
194 |
|
|
}
|
195 |
|
|
if (type & SPECIAL) {
|
196 |
|
|
if (base==8) {
|
197 |
|
|
if (buf <= end)
|
198 |
|
|
*buf = '0';
|
199 |
|
|
++buf;
|
200 |
|
|
} else if (base==16) {
|
201 |
|
|
if (buf <= end)
|
202 |
|
|
*buf = '0';
|
203 |
|
|
++buf;
|
204 |
|
|
if (buf <= end)
|
205 |
|
|
*buf = digits[33];
|
206 |
|
|
++buf;
|
207 |
|
|
}
|
208 |
|
|
}
|
209 |
|
|
if (!(type & LEFT)) {
|
210 |
|
|
while (size-- > 0) {
|
211 |
|
|
if (buf <= end)
|
212 |
|
|
*buf = c;
|
213 |
|
|
++buf;
|
214 |
|
|
}
|
215 |
|
|
}
|
216 |
|
|
while (i < precision--) {
|
217 |
|
|
if (buf <= end)
|
218 |
|
|
*buf = '0';
|
219 |
|
|
++buf;
|
220 |
|
|
}
|
221 |
|
|
while (i-- > 0) {
|
222 |
|
|
if (buf <= end)
|
223 |
|
|
*buf = tmp[i];
|
224 |
|
|
++buf;
|
225 |
|
|
}
|
226 |
|
|
while (size-- > 0) {
|
227 |
|
|
if (buf <= end)
|
228 |
|
|
*buf = ' ';
|
229 |
|
|
++buf;
|
230 |
|
|
}
|
231 |
|
|
return buf;
|
232 |
|
|
}
|
233 |
|
|
|
234 |
|
|
/**
|
235 |
|
|
* vsnprintf - Format a string and place it in a buffer
|
236 |
|
|
* @buf: The buffer to place the result into
|
237 |
|
|
* @size: The size of the buffer, including the trailing null space
|
238 |
|
|
* @fmt: The format string to use
|
239 |
|
|
* @args: Arguments for the format string
|
240 |
|
|
*
|
241 |
|
|
* The return value is the number of characters which would
|
242 |
|
|
* be generated for the given input, excluding the trailing
|
243 |
|
|
* '\0', as per ISO C99. If you want to have the exact
|
244 |
|
|
* number of characters written into @buf as return value
|
245 |
|
|
* (not including the trailing '\0'), use vscnprintf. If the
|
246 |
|
|
* return is greater than or equal to @size, the resulting
|
247 |
|
|
* string is truncated.
|
248 |
|
|
*
|
249 |
|
|
* Call this function if you are already dealing with a va_list.
|
250 |
|
|
* You probably want snprintf instead.
|
251 |
|
|
*/
|
252 |
|
|
int vsnprintf(char *buf, size_t size, const char *fmt, va_list args)
|
253 |
|
|
{
|
254 |
|
|
int len;
|
255 |
|
|
unsigned long long num;
|
256 |
|
|
int i, base;
|
257 |
|
|
char *str, *end, c;
|
258 |
|
|
const char *s;
|
259 |
|
|
|
260 |
|
|
int flags; /* flags to number() */
|
261 |
|
|
|
262 |
|
|
int field_width; /* width of output field */
|
263 |
|
|
int precision; /* min. # of digits for integers; max
|
264 |
|
|
number of chars for from string */
|
265 |
|
|
int qualifier; /* 'h', 'l', or 'L' for integer fields */
|
266 |
|
|
/* 'z' support added 23/7/1999 S.H. */
|
267 |
|
|
/* 'z' changed to 'Z' --davidm 1/25/99 */
|
268 |
|
|
/* 't' added for ptrdiff_t */
|
269 |
|
|
|
270 |
|
|
/* Reject out-of-range values early */
|
271 |
|
|
if ((int) size < 0) {
|
272 |
|
|
return 0;
|
273 |
|
|
}
|
274 |
|
|
|
275 |
|
|
str = buf;
|
276 |
|
|
end = buf + size - 1;
|
277 |
|
|
|
278 |
|
|
if (end < buf - 1) {
|
279 |
|
|
end = ((void *) -1);
|
280 |
|
|
size = end - buf + 1;
|
281 |
|
|
}
|
282 |
|
|
|
283 |
|
|
for (; *fmt ; ++fmt) {
|
284 |
|
|
if (*fmt != '%') {
|
285 |
|
|
if (str <= end)
|
286 |
|
|
*str = *fmt;
|
287 |
|
|
++str;
|
288 |
|
|
continue;
|
289 |
|
|
}
|
290 |
|
|
|
291 |
|
|
/* process flags */
|
292 |
|
|
flags = 0;
|
293 |
|
|
repeat:
|
294 |
|
|
++fmt; /* this also skips first '%' */
|
295 |
|
|
switch (*fmt) {
|
296 |
|
|
case '-': flags |= LEFT; goto repeat;
|
297 |
|
|
case '+': flags |= PLUS; goto repeat;
|
298 |
|
|
case ' ': flags |= SPACE; goto repeat;
|
299 |
|
|
case '#': flags |= SPECIAL; goto repeat;
|
300 |
|
|
case '0': flags |= ZEROPAD; goto repeat;
|
301 |
|
|
}
|
302 |
|
|
|
303 |
|
|
/* get field width */
|
304 |
|
|
field_width = -1;
|
305 |
|
|
if (isdigit(*fmt))
|
306 |
|
|
field_width = skip_atoi(&fmt);
|
307 |
|
|
else if (*fmt == '*') {
|
308 |
|
|
++fmt;
|
309 |
|
|
/* it's the next argument */
|
310 |
|
|
field_width = va_arg(args, int);
|
311 |
|
|
if (field_width < 0) {
|
312 |
|
|
field_width = -field_width;
|
313 |
|
|
flags |= LEFT;
|
314 |
|
|
}
|
315 |
|
|
}
|
316 |
|
|
|
317 |
|
|
/* get the precision */
|
318 |
|
|
precision = -1;
|
319 |
|
|
if (*fmt == '.') {
|
320 |
|
|
++fmt;
|
321 |
|
|
if (isdigit(*fmt))
|
322 |
|
|
precision = skip_atoi(&fmt);
|
323 |
|
|
else if (*fmt == '*') {
|
324 |
|
|
++fmt;
|
325 |
|
|
/* it's the next argument */
|
326 |
|
|
precision = va_arg(args, int);
|
327 |
|
|
}
|
328 |
|
|
if (precision < 0)
|
329 |
|
|
precision = 0;
|
330 |
|
|
}
|
331 |
|
|
|
332 |
|
|
/* get the conversion qualifier */
|
333 |
|
|
qualifier = -1;
|
334 |
|
|
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
|
335 |
|
|
*fmt =='Z' || *fmt == 'z' || *fmt == 't') {
|
336 |
|
|
qualifier = *fmt;
|
337 |
|
|
++fmt;
|
338 |
|
|
if (qualifier == 'l' && *fmt == 'l') {
|
339 |
|
|
qualifier = 'L';
|
340 |
|
|
++fmt;
|
341 |
|
|
}
|
342 |
|
|
}
|
343 |
|
|
|
344 |
|
|
/* default base */
|
345 |
|
|
base = 10;
|
346 |
|
|
|
347 |
|
|
switch (*fmt) {
|
348 |
|
|
case 'c':
|
349 |
|
|
if (!(flags & LEFT)) {
|
350 |
|
|
while (--field_width > 0) {
|
351 |
|
|
if (str <= end)
|
352 |
|
|
*str = ' ';
|
353 |
|
|
++str;
|
354 |
|
|
}
|
355 |
|
|
}
|
356 |
|
|
c = (unsigned char) va_arg(args, int);
|
357 |
|
|
if (str <= end)
|
358 |
|
|
*str = c;
|
359 |
|
|
++str;
|
360 |
|
|
while (--field_width > 0) {
|
361 |
|
|
if (str <= end)
|
362 |
|
|
*str = ' ';
|
363 |
|
|
++str;
|
364 |
|
|
}
|
365 |
|
|
continue;
|
366 |
|
|
|
367 |
|
|
case 's':
|
368 |
|
|
s = va_arg(args, char *);
|
369 |
|
|
|
370 |
|
|
len = strnlen(s, precision);
|
371 |
|
|
|
372 |
|
|
if (!(flags & LEFT)) {
|
373 |
|
|
while (len < field_width--) {
|
374 |
|
|
if (str <= end)
|
375 |
|
|
*str = ' ';
|
376 |
|
|
++str;
|
377 |
|
|
}
|
378 |
|
|
}
|
379 |
|
|
for (i = 0; i < len; ++i) {
|
380 |
|
|
if (str <= end)
|
381 |
|
|
*str = *s;
|
382 |
|
|
++str; ++s;
|
383 |
|
|
}
|
384 |
|
|
while (len < field_width--) {
|
385 |
|
|
if (str <= end)
|
386 |
|
|
*str = ' ';
|
387 |
|
|
++str;
|
388 |
|
|
}
|
389 |
|
|
continue;
|
390 |
|
|
|
391 |
|
|
case 'p':
|
392 |
|
|
if (field_width == -1) {
|
393 |
|
|
field_width = 2*sizeof(void *);
|
394 |
|
|
flags |= ZEROPAD;
|
395 |
|
|
}
|
396 |
|
|
str = number(str, end,
|
397 |
|
|
(unsigned long) va_arg(args, void *),
|
398 |
|
|
16, field_width, precision, flags);
|
399 |
|
|
continue;
|
400 |
|
|
|
401 |
|
|
|
402 |
|
|
case 'n':
|
403 |
|
|
/* FIXME:
|
404 |
|
|
* What does C99 say about the overflow case here? */
|
405 |
|
|
if (qualifier == 'l') {
|
406 |
|
|
long * ip = va_arg(args, long *);
|
407 |
|
|
*ip = (str - buf);
|
408 |
|
|
} else if (qualifier == 'Z' || qualifier == 'z') {
|
409 |
|
|
size_t * ip = va_arg(args, size_t *);
|
410 |
|
|
*ip = (str - buf);
|
411 |
|
|
} else {
|
412 |
|
|
int * ip = va_arg(args, int *);
|
413 |
|
|
*ip = (str - buf);
|
414 |
|
|
}
|
415 |
|
|
continue;
|
416 |
|
|
|
417 |
|
|
case '%':
|
418 |
|
|
if (str <= end)
|
419 |
|
|
*str = '%';
|
420 |
|
|
++str;
|
421 |
|
|
continue;
|
422 |
|
|
|
423 |
|
|
/* integer number formats - set up the flags and "break" */
|
424 |
|
|
case 'o':
|
425 |
|
|
base = 8;
|
426 |
|
|
break;
|
427 |
|
|
|
428 |
|
|
case 'X':
|
429 |
|
|
flags |= LARGE;
|
430 |
|
|
case 'x':
|
431 |
|
|
base = 16;
|
432 |
|
|
break;
|
433 |
|
|
|
434 |
|
|
case 'd':
|
435 |
|
|
case 'i':
|
436 |
|
|
flags |= SIGN;
|
437 |
|
|
case 'u':
|
438 |
|
|
break;
|
439 |
|
|
|
440 |
|
|
default:
|
441 |
|
|
if (str <= end)
|
442 |
|
|
*str = '%';
|
443 |
|
|
++str;
|
444 |
|
|
if (*fmt) {
|
445 |
|
|
if (str <= end)
|
446 |
|
|
*str = *fmt;
|
447 |
|
|
++str;
|
448 |
|
|
} else {
|
449 |
|
|
--fmt;
|
450 |
|
|
}
|
451 |
|
|
continue;
|
452 |
|
|
}
|
453 |
|
|
if (qualifier == 'L')
|
454 |
|
|
num = va_arg(args, long long);
|
455 |
|
|
else if (qualifier == 'l') {
|
456 |
|
|
num = va_arg(args, unsigned long);
|
457 |
|
|
if (flags & SIGN)
|
458 |
|
|
num = (signed long) num;
|
459 |
|
|
} else if (qualifier == 'Z' || qualifier == 'z') {
|
460 |
|
|
num = va_arg(args, size_t);
|
461 |
|
|
} else if (qualifier == 't') {
|
462 |
|
|
num = va_arg(args, ptrdiff_t);
|
463 |
|
|
} else if (qualifier == 'h') {
|
464 |
|
|
num = (unsigned short) va_arg(args, int);
|
465 |
|
|
if (flags & SIGN)
|
466 |
|
|
num = (signed short) num;
|
467 |
|
|
} else {
|
468 |
|
|
num = va_arg(args, unsigned int);
|
469 |
|
|
if (flags & SIGN)
|
470 |
|
|
num = (signed int) num;
|
471 |
|
|
}
|
472 |
|
|
str = number(str, end, num, base,
|
473 |
|
|
field_width, precision, flags);
|
474 |
|
|
}
|
475 |
|
|
if (str <= end)
|
476 |
|
|
*str = '\0';
|
477 |
|
|
else if (size > 0)
|
478 |
|
|
/* don't write out a null byte if the buf size is zero */
|
479 |
|
|
*end = '\0';
|
480 |
|
|
/* the trailing null byte doesn't count towards the total
|
481 |
|
|
* ++str;
|
482 |
|
|
*/
|
483 |
|
|
return str-buf;
|
484 |
|
|
}
|
485 |
|
|
|
486 |
|
|
|
487 |
|
|
/**
|
488 |
|
|
* vscnprintf - Format a string and place it in a buffer
|
489 |
|
|
* @buf: The buffer to place the result into
|
490 |
|
|
* @size: The size of the buffer, including the trailing null space
|
491 |
|
|
* @fmt: The format string to use
|
492 |
|
|
* @args: Arguments for the format string
|
493 |
|
|
*
|
494 |
|
|
* The return value is the number of characters which have been written into
|
495 |
|
|
* the @buf not including the trailing '\0'. If @size is <= 0 the function
|
496 |
|
|
* returns 0.
|
497 |
|
|
*
|
498 |
|
|
* Call this function if you are already dealing with a va_list.
|
499 |
|
|
* You probably want scnprintf instead.
|
500 |
|
|
*/
|
501 |
|
|
int vscnprintf(char *buf, size_t size, const char *fmt, va_list args)
|
502 |
|
|
{
|
503 |
7a651e94
|
laforge
|
unsigned int i;
|
504 |
2a2d6309
|
(no author)
|
|
505 |
|
|
i=vsnprintf(buf,size,fmt,args);
|
506 |
|
|
return (i >= size) ? (size - 1) : i;
|
507 |
|
|
}
|
508 |
|
|
|
509 |
|
|
|
510 |
|
|
/**
|
511 |
|
|
* snprintf - Format a string and place it in a buffer
|
512 |
|
|
* @buf: The buffer to place the result into
|
513 |
|
|
* @size: The size of the buffer, including the trailing null space
|
514 |
|
|
* @fmt: The format string to use
|
515 |
|
|
* @...: Arguments for the format string
|
516 |
|
|
*
|
517 |
|
|
* The return value is the number of characters which would be
|
518 |
|
|
* generated for the given input, excluding the trailing null,
|
519 |
|
|
* as per ISO C99. If the return is greater than or equal to
|
520 |
|
|
* @size, the resulting string is truncated.
|
521 |
|
|
*/
|
522 |
|
|
int snprintf(char * buf, size_t size, const char *fmt, ...)
|
523 |
|
|
{
|
524 |
|
|
va_list args;
|
525 |
|
|
int i;
|
526 |
|
|
|
527 |
|
|
va_start(args, fmt);
|
528 |
|
|
i=vsnprintf(buf,size,fmt,args);
|
529 |
|
|
va_end(args);
|
530 |
|
|
return i;
|
531 |
|
|
}
|
532 |
|
|
|
533 |
|
|
|
534 |
|
|
/**
|
535 |
|
|
* scnprintf - Format a string and place it in a buffer
|
536 |
|
|
* @buf: The buffer to place the result into
|
537 |
|
|
* @size: The size of the buffer, including the trailing null space
|
538 |
|
|
* @fmt: The format string to use
|
539 |
|
|
* @...: Arguments for the format string
|
540 |
|
|
*
|
541 |
|
|
* The return value is the number of characters written into @buf not including
|
542 |
|
|
* the trailing '\0'. If @size is <= 0 the function returns 0. If the return is
|
543 |
|
|
* greater than or equal to @size, the resulting string is truncated.
|
544 |
|
|
*/
|
545 |
|
|
|
546 |
|
|
int scnprintf(char * buf, size_t size, const char *fmt, ...)
|
547 |
|
|
{
|
548 |
|
|
va_list args;
|
549 |
7a651e94
|
laforge
|
unsigned int i;
|
550 |
2a2d6309
|
(no author)
|
|
551 |
|
|
va_start(args, fmt);
|
552 |
|
|
i = vsnprintf(buf, size, fmt, args);
|
553 |
|
|
va_end(args);
|
554 |
|
|
return (i >= size) ? (size - 1) : i;
|
555 |
|
|
}
|
556 |
|
|
|
557 |
|
|
/**
|
558 |
|
|
* vsprintf - Format a string and place it in a buffer
|
559 |
|
|
* @buf: The buffer to place the result into
|
560 |
|
|
* @fmt: The format string to use
|
561 |
|
|
* @args: Arguments for the format string
|
562 |
|
|
*
|
563 |
|
|
* The function returns the number of characters written
|
564 |
|
|
* into @buf. Use vsnprintf or vscnprintf in order to avoid
|
565 |
|
|
* buffer overflows.
|
566 |
|
|
*
|
567 |
|
|
* Call this function if you are already dealing with a va_list.
|
568 |
|
|
* You probably want sprintf instead.
|
569 |
|
|
*/
|
570 |
|
|
int vsprintf(char *buf, const char *fmt, va_list args)
|
571 |
|
|
{
|
572 |
|
|
return vsnprintf(buf, INT_MAX, fmt, args);
|
573 |
|
|
}
|
574 |
|
|
|
575 |
|
|
|
576 |
|
|
/**
|
577 |
|
|
* sprintf - Format a string and place it in a buffer
|
578 |
|
|
* @buf: The buffer to place the result into
|
579 |
|
|
* @fmt: The format string to use
|
580 |
|
|
* @...: Arguments for the format string
|
581 |
|
|
*
|
582 |
|
|
* The function returns the number of characters written
|
583 |
|
|
* into @buf. Use snprintf or scnprintf in order to avoid
|
584 |
|
|
* buffer overflows.
|
585 |
|
|
*/
|
586 |
|
|
int sprintf(char * buf, const char *fmt, ...)
|
587 |
|
|
{
|
588 |
|
|
va_list args;
|
589 |
|
|
int i;
|
590 |
|
|
|
591 |
|
|
va_start(args, fmt);
|
592 |
|
|
i=vsnprintf(buf, INT_MAX, fmt, args);
|
593 |
|
|
va_end(args);
|
594 |
|
|
return i;
|
595 |
|
|
}
|
596 |
|
|
|
597 |
|
|
|
598 |
|
|
/**
|
599 |
|
|
* vsscanf - Unformat a buffer into a list of arguments
|
600 |
|
|
* @buf: input buffer
|
601 |
|
|
* @fmt: format of buffer
|
602 |
|
|
* @args: arguments
|
603 |
|
|
*/
|
604 |
|
|
int vsscanf(const char * buf, const char * fmt, va_list args)
|
605 |
|
|
{
|
606 |
|
|
const char *str = buf;
|
607 |
|
|
char *next;
|
608 |
|
|
char digit;
|
609 |
|
|
int num = 0;
|
610 |
|
|
int qualifier;
|
611 |
|
|
int base;
|
612 |
|
|
int field_width;
|
613 |
|
|
int is_sign = 0;
|
614 |
|
|
|
615 |
|
|
while(*fmt && *str) {
|
616 |
|
|
/* skip any white space in format */
|
617 |
|
|
/* white space in format matchs any amount of
|
618 |
|
|
* white space, including none, in the input.
|
619 |
|
|
*/
|
620 |
|
|
if (isspace(*fmt)) {
|
621 |
|
|
while (isspace(*fmt))
|
622 |
|
|
++fmt;
|
623 |
|
|
while (isspace(*str))
|
624 |
|
|
++str;
|
625 |
|
|
}
|
626 |
|
|
|
627 |
|
|
/* anything that is not a conversion must match exactly */
|
628 |
|
|
if (*fmt != '%' && *fmt) {
|
629 |
|
|
if (*fmt++ != *str++)
|
630 |
|
|
break;
|
631 |
|
|
continue;
|
632 |
|
|
}
|
633 |
|
|
|
634 |
|
|
if (!*fmt)
|
635 |
|
|
break;
|
636 |
|
|
++fmt;
|
637 |
|
|
|
638 |
|
|
/* skip this conversion.
|
639 |
|
|
* advance both strings to next white space
|
640 |
|
|
*/
|
641 |
|
|
if (*fmt == '*') {
|
642 |
|
|
while (!isspace(*fmt) && *fmt)
|
643 |
|
|
fmt++;
|
644 |
|
|
while (!isspace(*str) && *str)
|
645 |
|
|
str++;
|
646 |
|
|
continue;
|
647 |
|
|
}
|
648 |
|
|
|
649 |
|
|
/* get field width */
|
650 |
|
|
field_width = -1;
|
651 |
|
|
if (isdigit(*fmt))
|
652 |
|
|
field_width = skip_atoi(&fmt);
|
653 |
|
|
|
654 |
|
|
/* get conversion qualifier */
|
655 |
|
|
qualifier = -1;
|
656 |
|
|
if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' ||
|
657 |
|
|
*fmt == 'Z' || *fmt == 'z') {
|
658 |
|
|
qualifier = *fmt++;
|
659 |
|
|
if (qualifier == *fmt) {
|
660 |
|
|
if (qualifier == 'h') {
|
661 |
|
|
qualifier = 'H';
|
662 |
|
|
fmt++;
|
663 |
|
|
} else if (qualifier == 'l') {
|
664 |
|
|
qualifier = 'L';
|
665 |
|
|
fmt++;
|
666 |
|
|
}
|
667 |
|
|
}
|
668 |
|
|
}
|
669 |
|
|
base = 10;
|
670 |
|
|
is_sign = 0;
|
671 |
|
|
|
672 |
|
|
if (!*fmt || !*str)
|
673 |
|
|
break;
|
674 |
|
|
|
675 |
|
|
switch(*fmt++) {
|
676 |
|
|
case 'c':
|
677 |
|
|
{
|
678 |
|
|
char *s = (char *) va_arg(args,char*);
|
679 |
|
|
if (field_width == -1)
|
680 |
|
|
field_width = 1;
|
681 |
|
|
do {
|
682 |
|
|
*s++ = *str++;
|
683 |
|
|
} while (--field_width > 0 && *str);
|
684 |
|
|
num++;
|
685 |
|
|
}
|
686 |
|
|
continue;
|
687 |
|
|
case 's':
|
688 |
|
|
{
|
689 |
|
|
char *s = (char *) va_arg(args, char *);
|
690 |
|
|
if(field_width == -1)
|
691 |
|
|
field_width = INT_MAX;
|
692 |
|
|
/* first, skip leading white space in buffer */
|
693 |
|
|
while (isspace(*str))
|
694 |
|
|
str++;
|
695 |
|
|
|
696 |
|
|
/* now copy until next white space */
|
697 |
|
|
while (*str && !isspace(*str) && field_width--) {
|
698 |
|
|
*s++ = *str++;
|
699 |
|
|
}
|
700 |
|
|
*s = '\0';
|
701 |
|
|
num++;
|
702 |
|
|
}
|
703 |
|
|
continue;
|
704 |
|
|
case 'n':
|
705 |
|
|
/* return number of characters read so far */
|
706 |
|
|
{
|
707 |
|
|
int *i = (int *)va_arg(args,int*);
|
708 |
|
|
*i = str - buf;
|
709 |
|
|
}
|
710 |
|
|
continue;
|
711 |
|
|
case 'o':
|
712 |
|
|
base = 8;
|
713 |
|
|
break;
|
714 |
|
|
case 'x':
|
715 |
|
|
case 'X':
|
716 |
|
|
base = 16;
|
717 |
|
|
break;
|
718 |
|
|
case 'i':
|
719 |
|
|
base = 0;
|
720 |
|
|
case 'd':
|
721 |
|
|
is_sign = 1;
|
722 |
|
|
case 'u':
|
723 |
|
|
break;
|
724 |
|
|
case '%':
|
725 |
|
|
/* looking for '%' in str */
|
726 |
|
|
if (*str++ != '%')
|
727 |
|
|
return num;
|
728 |
|
|
continue;
|
729 |
|
|
default:
|
730 |
|
|
/* invalid format; stop here */
|
731 |
|
|
return num;
|
732 |
|
|
}
|
733 |
|
|
|
734 |
|
|
/* have some sort of integer conversion.
|
735 |
|
|
* first, skip white space in buffer.
|
736 |
|
|
*/
|
737 |
|
|
while (isspace(*str))
|
738 |
|
|
str++;
|
739 |
|
|
|
740 |
|
|
digit = *str;
|
741 |
|
|
if (is_sign && digit == '-')
|
742 |
|
|
digit = *(str + 1);
|
743 |
|
|
|
744 |
|
|
if (!digit
|
745 |
|
|
|| (base == 16 && !isxdigit(digit))
|
746 |
|
|
|| (base == 10 && !isdigit(digit))
|
747 |
|
|
|| (base == 8 && (!isdigit(digit) || digit > '7'))
|
748 |
|
|
|| (base == 0 && !isdigit(digit)))
|
749 |
|
|
break;
|
750 |
|
|
|
751 |
|
|
switch(qualifier) {
|
752 |
|
|
case 'H': /* that's 'hh' in format */
|
753 |
|
|
if (is_sign) {
|
754 |
|
|
signed char *s = (signed char *) va_arg(args,signed char *);
|
755 |
|
|
*s = (signed char) simple_strtol(str,&next,base);
|
756 |
|
|
} else {
|
757 |
|
|
unsigned char *s = (unsigned char *) va_arg(args, unsigned char *);
|
758 |
|
|
*s = (unsigned char) simple_strtoul(str, &next, base);
|
759 |
|
|
}
|
760 |
|
|
break;
|
761 |
|
|
case 'h':
|
762 |
|
|
if (is_sign) {
|
763 |
|
|
short *s = (short *) va_arg(args,short *);
|
764 |
|
|
*s = (short) simple_strtol(str,&next,base);
|
765 |
|
|
} else {
|
766 |
|
|
unsigned short *s = (unsigned short *) va_arg(args, unsigned short *);
|
767 |
|
|
*s = (unsigned short) simple_strtoul(str, &next, base);
|
768 |
|
|
}
|
769 |
|
|
break;
|
770 |
|
|
case 'l':
|
771 |
|
|
if (is_sign) {
|
772 |
|
|
long *l = (long *) va_arg(args,long *);
|
773 |
|
|
*l = simple_strtol(str,&next,base);
|
774 |
|
|
} else {
|
775 |
|
|
unsigned long *l = (unsigned long*) va_arg(args,unsigned long*);
|
776 |
|
|
*l = simple_strtoul(str,&next,base);
|
777 |
|
|
}
|
778 |
|
|
break;
|
779 |
|
|
case 'L':
|
780 |
|
|
if (is_sign) {
|
781 |
|
|
long long *l = (long long*) va_arg(args,long long *);
|
782 |
|
|
*l = simple_strtoll(str,&next,base);
|
783 |
|
|
} else {
|
784 |
|
|
unsigned long long *l = (unsigned long long*) va_arg(args,unsigned long long*);
|
785 |
|
|
*l = simple_strtoull(str,&next,base);
|
786 |
|
|
}
|
787 |
|
|
break;
|
788 |
|
|
case 'Z':
|
789 |
|
|
case 'z':
|
790 |
|
|
{
|
791 |
|
|
size_t *s = (size_t*) va_arg(args,size_t*);
|
792 |
|
|
*s = (size_t) simple_strtoul(str,&next,base);
|
793 |
|
|
}
|
794 |
|
|
break;
|
795 |
|
|
default:
|
796 |
|
|
if (is_sign) {
|
797 |
|
|
int *i = (int *) va_arg(args, int*);
|
798 |
|
|
*i = (int) simple_strtol(str,&next,base);
|
799 |
|
|
} else {
|
800 |
|
|
unsigned int *i = (unsigned int*) va_arg(args, unsigned int*);
|
801 |
|
|
*i = (unsigned int) simple_strtoul(str,&next,base);
|
802 |
|
|
}
|
803 |
|
|
break;
|
804 |
|
|
}
|
805 |
|
|
num++;
|
806 |
|
|
|
807 |
|
|
if (!next)
|
808 |
|
|
break;
|
809 |
|
|
str = next;
|
810 |
|
|
}
|
811 |
|
|
return num;
|
812 |
|
|
}
|
813 |
|
|
|
814 |
|
|
|
815 |
|
|
/**
|
816 |
|
|
* sscanf - Unformat a buffer into a list of arguments
|
817 |
|
|
* @buf: input buffer
|
818 |
|
|
* @fmt: formatting of buffer
|
819 |
|
|
* @...: resulting arguments
|
820 |
|
|
*/
|
821 |
|
|
int sscanf(const char * buf, const char * fmt, ...)
|
822 |
|
|
{
|
823 |
|
|
va_list args;
|
824 |
|
|
int i;
|
825 |
|
|
|
826 |
|
|
va_start(args,fmt);
|
827 |
|
|
i = vsscanf(buf,fmt,args);
|
828 |
|
|
va_end(args);
|
829 |
|
|
return i;
|
830 |
|
|
}
|