1 // SPDX-License-Identifier: BSD-3-Clause
2 /*
3  * Copyright (c) 1990, 1993
4  * The Regents of the University of California. All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * Chris Torek.
8  *
9  * Copyright (c) 2011 The FreeBSD Foundation
10  * All rights reserved.
11  * Portions of this software were developed by David Chisnall
12  * under sponsorship from the FreeBSD Foundation.
13  *
14  * Author: Juergen Gross <jgross@suse.com>
15  * Date: Jun 2016
16  */
17 
18 #if !defined HAVE_LIBC
19 
20 #include <os.h>
21 #include <linux/kernel.h>
22 #include <linux/ctype.h>
23 #include <vsprintf.h>
24 #include <linux/string.h>
25 #include <malloc.h>
26 #define __DECONST(type, var)    ((type)(uintptr_t)(const void *)(var))
27 
28 /**
29  * struct str_info - Input string parameters
30  * @neg: negative number or not
31  *	 0 - not negative
32  *	 1 - negative
33  * @any: set any if any `digits' consumed; make it negative to indicate
34  *	 overflow
35  * @acc: accumulated value
36  */
37 struct str_info {
38 	int neg, any;
39 	u64 acc;
40 };
41 
42 /**
43  * str_to_int_convert() - Write string data to structure
44  * @nptr: pointer to string
45  * @base: number's base
46  * @unsign: describes what integer is expected
47  *	    0 - not unsigned
48  *	    1 - unsigned
49  *
50  * Ignores `locale' stuff.  Assumes that the upper and lower case
51  * alphabets and digits are each contiguous.
52  *
53  * Return: struct str_info *, which contains string data to future process
54  */
55 static struct str_info *
str_to_int_convert(const char ** nptr,int base,unsigned int unsign)56 str_to_int_convert(const char **nptr, int base, unsigned int unsign)
57 {
58 	const char *s = *nptr;
59 	u64 acc;
60 	unsigned char c;
61 	u64 cutoff;
62 	int neg, any, cutlim;
63 	u64 qbase;
64 	struct str_info *info;
65 
66 	/*
67 	 * Skip white space and pick up leading +/- sign if any.
68 	 * If base is 0, allow 0x for hex and 0 for octal, else
69 	 * assume decimal; if base is already 16, allow 0x.
70 	 */
71 	info = (struct str_info *)malloc(sizeof(struct str_info));
72 	if (!info)
73 		return NULL;
74 
75 	do {
76 		c = *s++;
77 	} while (isspace(c));
78 	if (c == '-') {
79 		neg = 1;
80 		c = *s++;
81 	} else {
82 		neg = 0;
83 		if (c == '+')
84 			c = *s++;
85 	}
86 	if ((base == 0 || base == 16) &&
87 	    c == '0' && (*s == 'x' || *s == 'X')) {
88 		c = s[1];
89 		s += 2;
90 		base = 16;
91 	}
92 	if (base == 0)
93 		base = c == '0' ? 8 : 10;
94 
95 	/*
96 	 * Compute the cutoff value between legal numbers and illegal
97 	 * numbers.  That is the largest legal value, divided by the
98 	 * base.  An input number that is greater than this value, if
99 	 * followed by a legal input character, is too big.  One that
100 	 * is equal to this value may be valid or not; the limit
101 	 * between valid and invalid numbers is then based on the last
102 	 * digit.  For instance, if the range for quads is
103 	 * [-9223372036854775808..9223372036854775807] and the input base
104 	 * is 10, cutoff will be set to 922337203685477580 and cutlim to
105 	 * either 7 (neg==0) or 8 (neg==1), meaning that if we have
106 	 * accumulated a value > 922337203685477580, or equal but the
107 	 * next digit is > 7 (or 8), the number is too big, and we will
108 	 * return a range error.
109 	 *
110 	 * Set any if any `digits' consumed; make it negative to indicate
111 	 * overflow.
112 	 */
113 	qbase = (unsigned int)base;
114 
115 	if (!unsign) {
116 		cutoff = neg ? (u64)-(LLONG_MIN + LLONG_MAX) + LLONG_MAX : LLONG_MAX;
117 		cutlim = cutoff % qbase;
118 		cutoff /= qbase;
119 	} else {
120 		cutoff = (u64)ULLONG_MAX / qbase;
121 		cutlim = (u64)ULLONG_MAX % qbase;
122 	}
123 
124 	for (acc = 0, any = 0;; c = *s++) {
125 		if (!isascii(c))
126 			break;
127 		if (isdigit(c))
128 			c -= '0';
129 		else if (isalpha(c))
130 			c -= isupper(c) ? 'A' - 10 : 'a' - 10;
131 		else
132 			break;
133 		if (c >= base)
134 			break;
135 		if (any < 0 || acc > cutoff || (acc == cutoff && c > cutlim)) {
136 			any = -1;
137 		} else {
138 			any = 1;
139 			acc *= qbase;
140 			acc += c;
141 		}
142 	}
143 
144 	info->any = any;
145 	info->neg = neg;
146 	info->acc = acc;
147 
148 	*nptr = s;
149 
150 	return info;
151 }
152 
153 /**
154  * strtoq() - Convert a string to a quad integer
155  * @nptr: pointer to string
156  * @endptr: pointer to number's end in the string
157  * @base: number's base
158  *
159  * Return: s64 quad integer number converted from input string
160  */
161 static s64
strtoq(const char * nptr,char ** endptr,int base)162 strtoq(const char *nptr, char **endptr, int base)
163 {
164 	const char *s = nptr;
165 	u64 acc;
166 	int unsign = 0;
167 	struct str_info *info;
168 
169 	info = str_to_int_convert(&s, base, unsign);
170 	if (!info)
171 		return -1;
172 
173 	acc = info->acc;
174 
175 	if (info->any < 0)
176 		acc = info->neg ? LLONG_MIN : LLONG_MAX;
177 	else if (info->neg)
178 		acc = -acc;
179 	if (endptr != 0)
180 		*endptr = __DECONST(char *, info->any ? s - 1 : nptr);
181 
182 	free(info);
183 
184 	return acc;
185 }
186 
187 /**
188  * strtouq() - Convert a string to an unsigned quad integer
189  * @nptr: pointer to string
190  * @endptr: pointer to number's end in the string
191  * @base: number's base
192  *
193  * Return: s64 unsigned quad integer number converted from
194  *         input string
195  */
196 u64
strtouq(const char * nptr,char ** endptr,int base)197 strtouq(const char *nptr, char **endptr, int base)
198 {
199 		const char *s = nptr;
200 	u64 acc;
201 	int unsign = 1;
202 	struct str_info *info;
203 
204 	info = str_to_int_convert(&s, base, unsign);
205 	if (!info)
206 		return -1;
207 
208 	acc = info->acc;
209 
210 	if (info->any < 0)
211 		acc = ULLONG_MAX;
212 	else if (info->neg)
213 		acc = -acc;
214 	if (endptr != 0)
215 		*endptr = __DECONST(char *, info->any ? s - 1 : nptr);
216 
217 	free(info);
218 
219 	return acc;
220 }
221 
222 /**
223  * __sccl() - Fill in the given table from the scanset at the given format
224  * (just after `[')
225  * @tab: table to fill in
226  * @fmt: format of buffer
227  *
228  * The table has a 1 wherever characters should be considered part of the
229  * scanset.
230  *
231  * Return: pointer to the character past the closing `]'
232  */
233 static const u_char *
__sccl(char * tab,const u_char * fmt)234 __sccl(char *tab, const u_char *fmt)
235 {
236 	int c, n, v;
237 
238 	/* first `clear' the whole table */
239 	c = *fmt++;             /* first char hat => negated scanset */
240 	if (c == '^') {
241 		v = 1;          /* default => accept */
242 		c = *fmt++;     /* get new first char */
243 	} else {
244 		v = 0;          /* default => reject */
245 	}
246 
247 	/* XXX: Will not work if sizeof(tab*) > sizeof(char) */
248 	for (n = 0; n < 256; n++)
249 		tab[n] = v;        /* memset(tab, v, 256) */
250 
251 	if (c == 0)
252 		return (fmt - 1);/* format ended before closing ] */
253 
254 	/*
255 	 * Now set the entries corresponding to the actual scanset
256 	 * to the opposite of the above.
257 	 *
258 	 * The first character may be ']' (or '-') without being special;
259 	 * the last character may be '-'.
260 	 */
261 	v = 1 - v;
262 	for (;;) {
263 		tab[c] = v;             /* take character c */
264 doswitch:
265 		n = *fmt++;             /* and examine the next */
266 		switch (n) {
267 		case 0:                 /* format ended too soon */
268 			return (fmt - 1);
269 
270 		case '-':
271 			/*
272 			 * A scanset of the form
273 			 *      [01+-]
274 			 * is defined as `the digit 0, the digit 1,
275 			 * the character +, the character -', but
276 			 * the effect of a scanset such as
277 			 *      [a-zA-Z0-9]
278 			 * is implementation defined.  The V7 Unix
279 			 * scanf treats `a-z' as `the letters a through
280 			 * z', but treats `a-a' as `the letter a, the
281 			 * character -, and the letter a'.
282 			 *
283 			 * For compatibility, the `-' is not considerd
284 			 * to define a range if the character following
285 			 * it is either a close bracket (required by ANSI)
286 			 * or is not numerically greater than the character
287 			 * we just stored in the table (c).
288 			 */
289 			n = *fmt;
290 			if (n == ']' || n < c) {
291 				c = '-';
292 				break;  /* resume the for(;;) */
293 			}
294 			fmt++;
295 			/* fill in the range */
296 			do {
297 				tab[++c] = v;
298 			} while (c < n);
299 			c = n;
300 			/*
301 			 * Alas, the V7 Unix scanf also treats formats
302 			 * such as [a-c-e] as `the letters a through e'.
303 			 * This too is permitted by the standard....
304 			 */
305 			goto doswitch;
306 			break;
307 
308 		case ']':               /* end of scanset */
309 			return (fmt);
310 
311 		default:                /* just another character */
312 			c = n;
313 			break;
314 		}
315 	}
316 	/* NOTREACHED */
317 }
318 
319 /**
320  * vsscanf - Unformat a buffer into a list of arguments
321  * @buf:	input buffer
322  * @fmt:	format of buffer
323  * @args:	arguments
324  */
325 #define BUF             32      /* Maximum length of numeric string. */
326 
327 /*
328  * Flags used during conversion.
329  */
330 #define LONG            0x01    /* l: long or double */
331 #define SHORT           0x04    /* h: short */
332 #define SUPPRESS        0x08    /* suppress assignment */
333 #define POINTER         0x10    /* weird %p pointer (`fake hex') */
334 #define NOSKIP          0x20    /* do not skip blanks */
335 #define QUAD            0x400
336 #define SHORTSHORT      0x4000  /** hh: char */
337 
338 /*
339  * The following are used in numeric conversions only:
340  * SIGNOK, NDIGITS, DPTOK, and EXPOK are for floating point;
341  * SIGNOK, NDIGITS, PFXOK, and NZDIGITS are for integral.
342  */
343 #define SIGNOK          0x40    /* +/- is (still) legal */
344 #define NDIGITS         0x80    /* no digits detected */
345 
346 #define DPTOK           0x100   /* (float) decimal point is still legal */
347 #define EXPOK           0x200   /* (float) exponent (e+3, etc) still legal */
348 
349 #define PFXOK           0x100   /* 0x prefix is (still) legal */
350 #define NZDIGITS        0x200   /* no zero digits detected */
351 
352 /*
353  * Conversion types.
354  */
355 #define CT_CHAR         0       /* %c conversion */
356 #define CT_CCL          1       /* %[...] conversion */
357 #define CT_STRING       2       /* %s conversion */
358 #define CT_INT          3       /* integer, i.e., strtoq or strtouq */
359 typedef u64 (*ccfntype)(const char *, char **, int);
360 
361 int
vsscanf(const char * inp,char const * fmt0,va_list ap)362 vsscanf(const char *inp, char const *fmt0, va_list ap)
363 {
364 	int inr;
365 	const u_char *fmt = (const u_char *)fmt0;
366 	int c;                  /* character from format, or conversion */
367 	size_t width;           /* field width, or 0 */
368 	char *p;                /* points into all kinds of strings */
369 	int n;                  /* handy integer */
370 	int flags;              /* flags as defined above */
371 	char *p0;               /* saves original value of p when necessary */
372 	int nassigned;          /* number of fields assigned */
373 	int nconversions;       /* number of conversions */
374 	int nread;              /* number of characters consumed from fp */
375 	int base;               /* base argument to strtoq/strtouq */
376 	ccfntype ccfn;          /* conversion function (strtoq/strtouq) */
377 	char ccltab[256];       /* character class table for %[...] */
378 	char buf[BUF];          /* buffer for numeric conversions */
379 
380 	/* `basefix' is used to avoid `if' tests in the integer scanner */
381 	static short basefix[17] = { 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
382 				     12, 13, 14, 15, 16 };
383 
384 	inr = strlen(inp);
385 
386 	nassigned = 0;
387 	nconversions = 0;
388 	nread = 0;
389 	base = 0;               /* XXX just to keep gcc happy */
390 	ccfn = NULL;            /* XXX just to keep gcc happy */
391 	for (;;) {
392 		c = *fmt++;
393 		if (c == 0)
394 			return (nassigned);
395 		if (isspace(c)) {
396 			while (inr > 0 && isspace(*inp))
397 				nread++, inr--, inp++;
398 			continue;
399 		}
400 		if (c != '%')
401 			goto literal;
402 		width = 0;
403 		flags = 0;
404 		/*
405 		 * switch on the format.  continue if done;
406 		 * break once format type is derived.
407 		 */
408 again:          c = *fmt++;
409 		switch (c) {
410 		case '%':
411 literal:
412 			if (inr <= 0)
413 				goto input_failure;
414 			if (*inp != c)
415 				goto match_failure;
416 			inr--, inp++;
417 			nread++;
418 			continue;
419 
420 		case '*':
421 			flags |= SUPPRESS;
422 			goto again;
423 		case 'l':
424 			if (flags & LONG) {
425 				flags &= ~LONG;
426 				flags |= QUAD;
427 			} else {
428 				flags |= LONG;
429 			}
430 			goto again;
431 		case 'q':
432 			flags |= QUAD;
433 			goto again;
434 		case 'h':
435 			if (flags & SHORT) {
436 				flags &= ~SHORT;
437 				flags |= SHORTSHORT;
438 			} else {
439 				flags |= SHORT;
440 			}
441 			goto again;
442 
443 		case '0': case '1': case '2': case '3': case '4':
444 		case '5': case '6': case '7': case '8': case '9':
445 			width = width * 10 + c - '0';
446 			goto again;
447 
448 		/*
449 		 * Conversions.
450 		 *
451 		 */
452 		case 'd':
453 			c = CT_INT;
454 			ccfn = (ccfntype)strtoq;
455 			base = 10;
456 			break;
457 
458 		case 'i':
459 			c = CT_INT;
460 			ccfn = (ccfntype)strtoq;
461 			base = 0;
462 			break;
463 
464 		case 'o':
465 			c = CT_INT;
466 			ccfn = strtouq;
467 			base = 8;
468 			break;
469 
470 		case 'u':
471 			c = CT_INT;
472 			ccfn = strtouq;
473 			base = 10;
474 			break;
475 
476 		case 'x':
477 			flags |= PFXOK; /* enable 0x prefixing */
478 			c = CT_INT;
479 			ccfn = strtouq;
480 			base = 16;
481 			break;
482 
483 		case 's':
484 			c = CT_STRING;
485 			break;
486 
487 		case '[':
488 			fmt = __sccl(ccltab, fmt);
489 			flags |= NOSKIP;
490 			c = CT_CCL;
491 			break;
492 
493 		case 'c':
494 			flags |= NOSKIP;
495 			c = CT_CHAR;
496 			break;
497 
498 		case 'p':       /* pointer format is like hex */
499 			flags |= POINTER | PFXOK;
500 			c = CT_INT;
501 			ccfn = strtouq;
502 			base = 16;
503 			break;
504 
505 		case 'n':
506 			nconversions++;
507 			if (flags & SUPPRESS)   /* ??? */
508 				continue;
509 			if (flags & SHORTSHORT)
510 				*va_arg(ap, char *) = nread;
511 			else if (flags & SHORT)
512 				*va_arg(ap, short *) = nread;
513 			else if (flags & LONG)
514 				*va_arg(ap, long *) = nread;
515 			else if (flags & QUAD)
516 				*va_arg(ap, s64 *) = nread;
517 			else
518 				*va_arg(ap, int *) = nread;
519 			continue;
520 		}
521 
522 		/*
523 		 * We have a conversion that requires input.
524 		 */
525 		if (inr <= 0)
526 			goto input_failure;
527 
528 		/*
529 		 * Consume leading white space, except for formats
530 		 * that suppress this.
531 		 */
532 		if ((flags & NOSKIP) == 0) {
533 			while (isspace(*inp)) {
534 				nread++;
535 				if (--inr > 0)
536 					inp++;
537 				else
538 					goto input_failure;
539 			}
540 			/*
541 			 * Note that there is at least one character in
542 			 * the buffer, so conversions that do not set NOSKIP
543 			 * can no longer result in an input failure.
544 			 */
545 		}
546 
547 		/*
548 		 * Do the conversion.
549 		 */
550 		switch (c) {
551 		case CT_CHAR:
552 			/* scan arbitrary characters (sets NOSKIP) */
553 			if (width == 0)
554 				width = 1;
555 			if (flags & SUPPRESS) {
556 				size_t sum = 0;
557 
558 				n = inr;
559 				if (n < width) {
560 					sum += n;
561 					width -= n;
562 					inp += n;
563 					if (sum == 0)
564 						goto input_failure;
565 				} else {
566 					sum += width;
567 					inr -= width;
568 					inp += width;
569 				}
570 				nread += sum;
571 			} else {
572 				memcpy(va_arg(ap, char *), inp, width);
573 				inr -= width;
574 				inp += width;
575 				nread += width;
576 				nassigned++;
577 			}
578 			nconversions++;
579 			break;
580 
581 		case CT_CCL:
582 			/* scan a (nonempty) character class (sets NOSKIP) */
583 			if (width == 0)
584 				width = (size_t)~0;     /* `infinity' */
585 			/* take only those things in the class */
586 			if (flags & SUPPRESS) {
587 				n = 0;
588 				while (ccltab[(unsigned char)*inp]) {
589 					n++, inr--, inp++;
590 					if (--width == 0)
591 						break;
592 					if (inr <= 0) {
593 						if (n == 0)
594 							goto input_failure;
595 						break;
596 					}
597 				}
598 				if (n == 0)
599 					goto match_failure;
600 			} else {
601 				p = va_arg(ap, char *);
602 				p0 = p;
603 				while (ccltab[(unsigned char)*inp]) {
604 					inr--;
605 					*p++ = *inp++;
606 					if (--width == 0)
607 						break;
608 					if (inr <= 0) {
609 						if (p == p0)
610 							goto input_failure;
611 						break;
612 					}
613 				}
614 				n = p - p0;
615 				if (n == 0)
616 					goto match_failure;
617 				*p = 0;
618 				nassigned++;
619 			}
620 			nread += n;
621 			nconversions++;
622 			break;
623 
624 		case CT_STRING:
625 			/* like CCL, but zero-length string OK, & no NOSKIP */
626 			if (width == 0)
627 				width = (size_t)~0;
628 			if (flags & SUPPRESS) {
629 				n = 0;
630 				while (!isspace(*inp)) {
631 					n++, inr--, inp++;
632 					if (--width == 0)
633 						break;
634 					if (inr <= 0)
635 						break;
636 				}
637 				nread += n;
638 			} else {
639 				p = va_arg(ap, char *);
640 				p0 = p;
641 				while (!isspace(*inp)) {
642 					inr--;
643 					*p++ = *inp++;
644 					if (--width == 0)
645 						break;
646 					if (inr <= 0)
647 						break;
648 				}
649 				*p = 0;
650 				nread += p - p0;
651 				nassigned++;
652 			}
653 			nconversions++;
654 			continue;
655 
656 		case CT_INT:
657 			/* scan an integer as if by strtoq/strtouq */
658 #ifdef hardway
659 			if (width == 0 || width > sizeof(buf) - 1)
660 				width = sizeof(buf) - 1;
661 #else
662 			/* size_t is unsigned, hence this optimisation */
663 			if (--width > sizeof(buf) - 2)
664 				width = sizeof(buf) - 2;
665 			width++;
666 #endif
667 			flags |= SIGNOK | NDIGITS | NZDIGITS;
668 			for (p = buf; width; width--) {
669 				c = *inp;
670 				/*
671 				 * Switch on the character; `goto ok'
672 				 * if we accept it as a part of number.
673 				 */
674 				switch (c) {
675 				/*
676 				 * The digit 0 is always legal, but is
677 				 * special.  For %i conversions, if no
678 				 * digits (zero or nonzero) have been
679 				 * scanned (only signs), we will have
680 				 * base==0.  In that case, we should set
681 				 * it to 8 and enable 0x prefixing.
682 				 * Also, if we have not scanned zero digits
683 				 * before this, do not turn off prefixing
684 				 * (someone else will turn it off if we
685 				 * have scanned any nonzero digits).
686 				 */
687 				case '0':
688 					if (base == 0) {
689 						base = 8;
690 						flags |= PFXOK;
691 					}
692 					if (flags & NZDIGITS)
693 						flags &= ~(SIGNOK | NZDIGITS | NDIGITS);
694 					else
695 						flags &= ~(SIGNOK | PFXOK | NDIGITS);
696 					goto ok;
697 
698 				/* 1 through 7 always legal */
699 				case '1': case '2': case '3':
700 				case '4': case '5': case '6': case '7':
701 					base = basefix[base];
702 					flags &= ~(SIGNOK | PFXOK | NDIGITS);
703 					goto ok;
704 
705 				/* digits 8 and 9 ok iff decimal or hex */
706 				case '8': case '9':
707 					base = basefix[base];
708 					if (base <= 8)
709 						break;  /* not legal here */
710 					flags &= ~(SIGNOK | PFXOK | NDIGITS);
711 					goto ok;
712 
713 				/* letters ok iff hex */
714 				case 'A': case 'B': case 'C':
715 				case 'D': case 'E': case 'F':
716 				case 'a': case 'b': case 'c':
717 				case 'd': case 'e': case 'f':
718 					/* no need to fix base here */
719 					if (base <= 10)
720 						break;  /* not legal here */
721 					flags &= ~(SIGNOK | PFXOK | NDIGITS);
722 					goto ok;
723 
724 				/* sign ok only as first character */
725 				case '+': case '-':
726 					if (flags & SIGNOK) {
727 						flags &= ~SIGNOK;
728 						goto ok;
729 						}
730 					break;
731 
732 				/* x ok iff flag still set & 2nd char */
733 				case 'x': case 'X':
734 					if (flags & PFXOK && p == buf + 1) {
735 						base = 16;      /* if %i */
736 						flags &= ~PFXOK;
737 						goto ok;
738 					}
739 					break;
740 				}
741 
742 				/*
743 				 * If we got here, c is not a legal character
744 				 * for a number.  Stop accumulating digits.
745 				 */
746 				break;
747 ok:
748 				/*
749 				 * c is legal: store it and look at the next.
750 				 */
751 				*p++ = c;
752 				if (--inr > 0)
753 					inp++;
754 				else
755 					break;          /* end of input */
756 			}
757 			/*
758 			 * If we had only a sign, it is no good; push
759 			 * back the sign.  If the number ends in `x',
760 			 * it was [sign] '' 'x', so push back the x
761 			 * and treat it as [sign] ''.
762 			 */
763 			if (flags & NDIGITS) {
764 				if (p > buf) {
765 					inp--;
766 					inr++;
767 				}
768 				goto match_failure;
769 			}
770 			c = ((u_char *)p)[-1];
771 			if (c == 'x' || c == 'X') {
772 				--p;
773 				inp--;
774 				inr++;
775 			}
776 			if ((flags & SUPPRESS) == 0) {
777 				u64 res;
778 
779 				*p = 0;
780 				res = (*ccfn)(buf, (char **)NULL, base);
781 				if (flags & POINTER)
782 					*va_arg(ap, void **) =
783 					(void *)(uintptr_t)res;
784 				else if (flags & SHORTSHORT)
785 					*va_arg(ap, char *) = res;
786 				else if (flags & SHORT)
787 					*va_arg(ap, short *) = res;
788 				else if (flags & LONG)
789 					*va_arg(ap, long *) = res;
790 				else if (flags & QUAD)
791 					*va_arg(ap, s64 *) = res;
792 				else
793 					*va_arg(ap, int *) = res;
794 				nassigned++;
795 			}
796 			nread += p - buf;
797 			nconversions++;
798 			break;
799 		}
800 	}
801 input_failure:
802 		return (nconversions != 0 ? nassigned : -1);
803 match_failure:
804 		return (nassigned);
805 }
806 
807 /**
808  * sscanf - Unformat a buffer into a list of arguments
809  * @buf:	input buffer
810  * @fmt:	formatting of buffer
811  * @...:	resulting arguments
812  */
sscanf(const char * buf,const char * fmt,...)813 int sscanf(const char *buf, const char *fmt, ...)
814 {
815 	va_list args;
816 	int i;
817 
818 	va_start(args, fmt);
819 	i = vsscanf(buf, fmt, args);
820 	va_end(args);
821 	return i;
822 }
823 
824 #endif
825