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>
29 #define unlikely(x) (x)
32 * skip_spaces - Removes leading whitespace from @str.
33 * @str: The string to be stripped.
35 * Returns a pointer to the first non-whitespace character in @str.
37 static char *skip_spaces(const char *str)
44 static int skip_atoi(const char **s)
49 i = i*10 + *((*s)++) - '0';
54 const char *_parse_integer_fixup_radix(const char *s, unsigned int *base)
58 if (_tolower(s[1]) == 'x' && isxdigit(s[2]))
65 if (*base == 16 && s[0] == '0' && _tolower(s[1]) == 'x')
71 * vsscanf - Unformat a buffer into a list of arguments
73 * @fmt: format of buffer
76 int vsscanf(const char *buf, const char *fmt, va_list args)
78 const char *str = buf;
92 /* skip any white space in format */
93 /* white space in format matchs any amount of
94 * white space, including none, in the input.
97 fmt = skip_spaces(++fmt);
98 str = skip_spaces(str);
101 /* anything that is not a conversion must match exactly */
102 if (*fmt != '%' && *fmt) {
103 if (*fmt++ != *str++)
112 /* skip this conversion.
113 * advance both strings to next white space
118 while (!isspace(*fmt) && *fmt != '%' && *fmt)
120 while (!isspace(*str) && *str)
125 /* get field width */
128 field_width = skip_atoi(&fmt);
129 if (field_width <= 0)
133 /* get conversion qualifier */
135 if (*fmt == 'h' || _tolower(*fmt) == 'l' ||
136 _tolower(*fmt) == 'z') {
138 if (unlikely(qualifier == *fmt)) {
139 if (qualifier == 'h') {
142 } else if (qualifier == 'l') {
153 /* return number of characters read so far */
154 *va_arg(args, int *) = str - buf;
168 char *s = (char *)va_arg(args, char*);
169 if (field_width == -1)
173 } while (--field_width > 0 && *str);
179 char *s = (char *)va_arg(args, char *);
180 if (field_width == -1)
181 field_width = INT16_MAX;
182 /* first, skip leading white space in buffer */
183 str = skip_spaces(str);
185 /* now copy until next white space */
186 while (*str && !isspace(*str) && field_width--)
206 /* looking for '%' in str */
211 /* invalid format; stop here */
215 /* have some sort of integer conversion.
216 * first, skip white space in buffer.
218 str = skip_spaces(str);
221 if (is_sign && digit == '-')
225 || (base == 16 && !isxdigit(digit))
226 || (base == 10 && !isdigit(digit))
227 || (base == 8 && (!isdigit(digit) || digit > '7'))
228 || (base == 0 && !isdigit(digit)))
233 val.s = qualifier != 'L' ?
234 strtol(str, &next, base) :
235 strtoll(str, &next, base);
237 val.s = strtol(str, &next, base);
241 val.u = qualifier != 'L' ?
242 strtoul(str, &next, base) :
243 strtoull(str, &next, base);
245 val.s = strtoul(str, &next, base);
248 if (field_width > 0 && next - str > field_width) {
250 _parse_integer_fixup_radix(str, &base);
251 while (next - str > field_width) {
252 if (is_sign) // AKAROS_PORT
253 val.s = (int64_t)(val.s / base);
255 val.u = (uint64_t)(val.u / base);
261 case 'H': /* that's 'hh' in format */
263 *va_arg(args, signed char *) = val.s;
265 *va_arg(args, unsigned char *) = val.u;
269 *va_arg(args, short *) = val.s;
271 *va_arg(args, unsigned short *) = val.u;
275 *va_arg(args, long *) = val.s;
277 *va_arg(args, unsigned long *) = val.u;
281 *va_arg(args, long long *) = val.s;
283 *va_arg(args, unsigned long long *) = val.u;
287 *va_arg(args, size_t *) = val.u;
291 *va_arg(args, int *) = val.s;
293 *va_arg(args, unsigned int *) = val.u;
307 * sscanf - Unformat a buffer into a list of arguments
309 * @fmt: formatting of buffer
310 * @...: resulting arguments
312 int sscanf(const char *buf, const char *fmt, ...)
318 i = vsscanf(buf, fmt, args);