4 * Copyright (C) 1991, 1992 Linus Torvalds
7 /* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */
9 * Wirzenius wrote this portably, Torvalds fucked it up :-)
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
19 /* (trimmed to just scanf for Akaros). grep AKAROS_PORT for dirty hacks */
21 #include <ros/common.h>
30 * skip_spaces - Removes leading whitespace from @str.
31 * @str: The string to be stripped.
33 * Returns a pointer to the first non-whitespace character in @str.
35 static char *skip_spaces(const char *str)
42 static int skip_atoi(const char **s)
47 i = i*10 + *((*s)++) - '0';
52 const char *_parse_integer_fixup_radix(const char *s, unsigned int *base)
56 if (_tolower(s[1]) == 'x' && isxdigit(s[2]))
63 if (*base == 16 && s[0] == '0' && _tolower(s[1]) == 'x')
69 * vsscanf - Unformat a buffer into a list of arguments
71 * @fmt: format of buffer
74 int vsscanf(const char *buf, const char *fmt, va_list args)
76 const char *str = buf;
90 /* skip any white space in format */
91 /* white space in format matchs any amount of
92 * white space, including none, in the input.
95 fmt = skip_spaces(++fmt);
96 str = skip_spaces(str);
99 /* anything that is not a conversion must match exactly */
100 if (*fmt != '%' && *fmt) {
101 if (*fmt++ != *str++)
110 /* skip this conversion.
111 * advance both strings to next white space
116 while (!isspace(*fmt) && *fmt != '%' && *fmt)
118 while (!isspace(*str) && *str)
123 /* get field width */
126 field_width = skip_atoi(&fmt);
127 if (field_width <= 0)
131 /* get conversion qualifier */
133 if (*fmt == 'h' || _tolower(*fmt) == 'l' ||
134 _tolower(*fmt) == 'z') {
136 if (unlikely(qualifier == *fmt)) {
137 if (qualifier == 'h') {
140 } else if (qualifier == 'l') {
151 /* return number of characters read so far */
152 *va_arg(args, int *) = str - buf;
166 char *s = (char *)va_arg(args, char*);
167 if (field_width == -1)
171 } while (--field_width > 0 && *str);
177 char *s = (char *)va_arg(args, char *);
178 if (field_width == -1)
179 field_width = INT16_MAX;
180 /* first, skip leading white space in buffer */
181 str = skip_spaces(str);
183 /* now copy until next white space */
184 while (*str && !isspace(*str) && field_width--)
204 /* looking for '%' in str */
209 /* invalid format; stop here */
213 /* have some sort of integer conversion.
214 * first, skip white space in buffer.
216 str = skip_spaces(str);
219 if (is_sign && digit == '-')
223 || (base == 16 && !isxdigit(digit))
224 || (base == 10 && !isdigit(digit))
225 || (base == 8 && (!isdigit(digit) || digit > '7'))
226 || (base == 0 && !isdigit(digit)))
231 val.s = qualifier != 'L' ?
232 strtol(str, &next, base) :
233 strtoll(str, &next, base);
235 val.s = strtol(str, &next, base);
239 val.u = qualifier != 'L' ?
240 strtoul(str, &next, base) :
241 strtoull(str, &next, base);
243 val.s = strtoul(str, &next, base);
246 if (field_width > 0 && next - str > field_width) {
248 _parse_integer_fixup_radix(str, &base);
249 while (next - str > field_width) {
250 if (is_sign) // AKAROS_PORT
251 val.s = (int64_t)(val.s / base);
253 val.u = (uint64_t)(val.u / base);
259 case 'H': /* that's 'hh' in format */
261 *va_arg(args, signed char *) = val.s;
263 *va_arg(args, unsigned char *) = val.u;
267 *va_arg(args, short *) = val.s;
269 *va_arg(args, unsigned short *) = val.u;
273 *va_arg(args, long *) = val.s;
275 *va_arg(args, unsigned long *) = val.u;
279 *va_arg(args, long long *) = val.s;
281 *va_arg(args, unsigned long long *) = val.u;
285 *va_arg(args, size_t *) = val.u;
289 *va_arg(args, int *) = val.s;
291 *va_arg(args, unsigned int *) = val.u;
305 * sscanf - Unformat a buffer into a list of arguments
307 * @fmt: formatting of buffer
308 * @...: resulting arguments
310 int sscanf(const char *buf, const char *fmt, ...)
316 i = vsscanf(buf, fmt, args);