Project

General

Profile

Download (18 KB) Statistics
| Branch: | Tag: | Revision:
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
}
Add picture from clipboard (Maximum size: 48.8 MB)