Skip to content
vsprintf.c 53.1 KiB
Newer Older
}
EXPORT_SYMBOL_GPL(bstr_printf);

/**
 * bprintf - Parse a format string and place args' binary value in a buffer
 * @bin_buf: The buffer to place args' binary value
 * @size: The size of the buffer(by words(32bits), not characters)
 * @fmt: The format string to use
 * @...: Arguments for the format string
 *
 * The function returns the number of words(u32) written
 * into @bin_buf.
 */
int bprintf(u32 *bin_buf, size_t size, const char *fmt, ...)
{
	va_list args;
	int ret;

	va_start(args, fmt);
	ret = vbin_printf(bin_buf, size, fmt, args);
	va_end(args);
	return ret;
}
EXPORT_SYMBOL_GPL(bprintf);

#endif /* CONFIG_BINARY_PRINTF */

Linus Torvalds's avatar
Linus Torvalds committed
/**
 * vsscanf - Unformat a buffer into a list of arguments
 * @buf:	input buffer
 * @fmt:	format of buffer
 * @args:	arguments
 */
int vsscanf(const char *buf, const char *fmt, va_list args)
Linus Torvalds's avatar
Linus Torvalds committed
{
	const char *str = buf;
	char *next;
	char digit;
	int num = 0;
	unsigned int base;
	union {
		long long s;
		unsigned long long u;
	} val;
Linus Torvalds's avatar
Linus Torvalds committed

Linus Torvalds's avatar
Linus Torvalds committed
		/* skip any white space in format */
		/* white space in format matchs any amount of
		 * white space, including none, in the input.
		 */
		if (isspace(*fmt)) {
			fmt = skip_spaces(++fmt);
			str = skip_spaces(str);
Linus Torvalds's avatar
Linus Torvalds committed
		}

		/* anything that is not a conversion must match exactly */
		if (*fmt != '%' && *fmt) {
			if (*fmt++ != *str++)
				break;
			continue;
		}

		if (!*fmt)
			break;
		++fmt;
Linus Torvalds's avatar
Linus Torvalds committed
		/* skip this conversion.
		 * advance both strings to next white space
		 */
		if (*fmt == '*') {
Andy Spencer's avatar
Andy Spencer committed
			while (!isspace(*fmt) && *fmt != '%' && *fmt)
Linus Torvalds's avatar
Linus Torvalds committed
				fmt++;
			while (!isspace(*str) && *str)
				str++;
			continue;
		}

		/* get field width */
		field_width = -1;
Linus Torvalds's avatar
Linus Torvalds committed
			field_width = skip_atoi(&fmt);
Linus Torvalds's avatar
Linus Torvalds committed

		/* get conversion qualifier */
		qualifier = -1;
		if (*fmt == 'h' || _tolower(*fmt) == 'l' ||
		    _tolower(*fmt) == 'z') {
Linus Torvalds's avatar
Linus Torvalds committed
			qualifier = *fmt++;
			if (unlikely(qualifier == *fmt)) {
				if (qualifier == 'h') {
					qualifier = 'H';
					fmt++;
				} else if (qualifier == 'l') {
					qualifier = 'L';
					fmt++;
				}
			}
		}

		if (!*fmt)
			break;

		if (*fmt == 'n') {
			/* return number of characters read so far */
			*va_arg(args, int *) = str - buf;
			++fmt;
			continue;
		}

		if (!*str)
Linus Torvalds's avatar
Linus Torvalds committed
			break;

Linus Torvalds's avatar
Linus Torvalds committed
		case 'c':
		{
			char *s = (char *)va_arg(args, char*);
Linus Torvalds's avatar
Linus Torvalds committed
			if (field_width == -1)
				field_width = 1;
			do {
				*s++ = *str++;
			} while (--field_width > 0 && *str);
			num++;
		}
		continue;
		case 's':
		{
			char *s = (char *)va_arg(args, char *);
			if (field_width == -1)
Linus Torvalds's avatar
Linus Torvalds committed
			/* first, skip leading white space in buffer */
Linus Torvalds's avatar
Linus Torvalds committed

			/* now copy until next white space */
			while (*str && !isspace(*str) && field_width--)
Linus Torvalds's avatar
Linus Torvalds committed
				*s++ = *str++;
			*s = '\0';
			num++;
		}
		continue;
		case 'o':
			base = 8;
			break;
		case 'x':
		case 'X':
			base = 16;
			break;
		case 'i':
Linus Torvalds's avatar
Linus Torvalds committed
		case 'd':
			is_sign = 1;
		case 'u':
			break;
		case '%':
			/* looking for '%' in str */
Linus Torvalds's avatar
Linus Torvalds committed
				return num;
			continue;
		default:
			/* invalid format; stop here */
			return num;
		}

		/* have some sort of integer conversion.
		 * first, skip white space in buffer.
		 */
Linus Torvalds's avatar
Linus Torvalds committed

		digit = *str;
		if (is_sign && digit == '-')
			digit = *(str + 1);

		if (!digit
		    || (base == 16 && !isxdigit(digit))
		    || (base == 10 && !isdigit(digit))
		    || (base == 8 && (!isdigit(digit) || digit > '7'))
		    || (base == 0 && !isdigit(digit)))
			break;
Linus Torvalds's avatar
Linus Torvalds committed

		if (is_sign)
			val.s = qualifier != 'L' ?
				simple_strtol(str, &next, base) :
				simple_strtoll(str, &next, base);
		else
			val.u = qualifier != 'L' ?
				simple_strtoul(str, &next, base) :
				simple_strtoull(str, &next, base);

		if (field_width > 0 && next - str > field_width) {
			if (base == 0)
				_parse_integer_fixup_radix(str, &base);
			while (next - str > field_width) {
				if (is_sign)
					val.s = div_s64(val.s, base);
				else
					val.u = div_u64(val.u, base);
				--next;
			}
		}

Linus Torvalds's avatar
Linus Torvalds committed
		case 'H':	/* that's 'hh' in format */
			if (is_sign)
				*va_arg(args, signed char *) = val.s;
			else
				*va_arg(args, unsigned char *) = val.u;
Linus Torvalds's avatar
Linus Torvalds committed
			break;
		case 'h':
			if (is_sign)
				*va_arg(args, short *) = val.s;
			else
				*va_arg(args, unsigned short *) = val.u;
Linus Torvalds's avatar
Linus Torvalds committed
			break;
		case 'l':
			if (is_sign)
				*va_arg(args, long *) = val.s;
			else
				*va_arg(args, unsigned long *) = val.u;
Linus Torvalds's avatar
Linus Torvalds committed
			break;
		case 'L':
			if (is_sign)
				*va_arg(args, long long *) = val.s;
			else
				*va_arg(args, unsigned long long *) = val.u;
Linus Torvalds's avatar
Linus Torvalds committed
			break;
		case 'Z':
		case 'z':
			*va_arg(args, size_t *) = val.u;
			break;
Linus Torvalds's avatar
Linus Torvalds committed
		default:
			if (is_sign)
				*va_arg(args, int *) = val.s;
			else
				*va_arg(args, unsigned int *) = val.u;
Linus Torvalds's avatar
Linus Torvalds committed
			break;
		}
		num++;

		if (!next)
			break;
		str = next;
	}
Linus Torvalds's avatar
Linus Torvalds committed
	return num;
}
EXPORT_SYMBOL(vsscanf);

/**
 * sscanf - Unformat a buffer into a list of arguments
 * @buf:	input buffer
 * @fmt:	formatting of buffer
 * @...:	resulting arguments
 */
int sscanf(const char *buf, const char *fmt, ...)
Linus Torvalds's avatar
Linus Torvalds committed
{
	va_list args;
	int i;

	va_start(args, fmt);
	i = vsscanf(buf, fmt, args);
Linus Torvalds's avatar
Linus Torvalds committed
	va_end(args);
Linus Torvalds's avatar
Linus Torvalds committed
	return i;
}
EXPORT_SYMBOL(sscanf);