2023-06-18 21:44:30 +00:00
|
|
|
#include <luna/CType.h>
|
|
|
|
#include <luna/NumberParsing.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#define FLAG_DISCARD (1 << 0)
|
|
|
|
#define FLAG_ALLOC (1 << 1)
|
|
|
|
#define FLAG_WIDTH (1 << 2)
|
|
|
|
|
|
|
|
static int parse_flags(const char** format)
|
|
|
|
{
|
|
|
|
int result = 0;
|
|
|
|
|
|
|
|
while (true)
|
|
|
|
{
|
|
|
|
switch (**format)
|
|
|
|
{
|
|
|
|
case '*':
|
|
|
|
result |= FLAG_DISCARD;
|
|
|
|
(*format)++;
|
|
|
|
break;
|
|
|
|
case 'm':
|
|
|
|
result |= FLAG_ALLOC;
|
|
|
|
(*format)++;
|
|
|
|
break;
|
|
|
|
default: return result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static size_t parse_width(const char** format, int& flags)
|
|
|
|
{
|
|
|
|
size_t result = 0;
|
|
|
|
|
|
|
|
if (_isdigit(**format))
|
|
|
|
{
|
|
|
|
result = scan_unsigned_integer(format);
|
|
|
|
flags |= FLAG_WIDTH;
|
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
extern "C"
|
|
|
|
{
|
|
|
|
int vsscanf(const char* str, const char* format, va_list ap)
|
|
|
|
{
|
|
|
|
int parsed = 0;
|
|
|
|
|
|
|
|
if (*str == 0) return EOF;
|
|
|
|
|
|
|
|
while (*format)
|
|
|
|
{
|
|
|
|
if (*format != '%')
|
|
|
|
{
|
|
|
|
normal:
|
|
|
|
if (!_isspace(*format))
|
|
|
|
{
|
|
|
|
if (*str != *format) return parsed;
|
|
|
|
str++;
|
|
|
|
format++;
|
|
|
|
if (*str == 0) return parsed;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
format += strspn(format, " \t\f\r\n\v");
|
|
|
|
str += strspn(str, " \t\f\r\n\v");
|
|
|
|
if (*str == 0) return parsed;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
format++;
|
2023-06-18 21:51:44 +00:00
|
|
|
if (*format == '%')
|
|
|
|
{
|
|
|
|
str += strspn(str, " \t\f\r\n\v");
|
|
|
|
goto normal;
|
|
|
|
}
|
2023-06-18 21:44:30 +00:00
|
|
|
|
|
|
|
int flags = parse_flags(&format);
|
|
|
|
size_t width = parse_width(&format, flags);
|
|
|
|
char specifier = *format++;
|
|
|
|
if (!specifier) return parsed;
|
|
|
|
|
|
|
|
switch (specifier)
|
|
|
|
{
|
|
|
|
case 's': {
|
|
|
|
str += strspn(str, " \t\f\r\n\v");
|
|
|
|
size_t chars = strcspn(str, " \t\f\r\n\v");
|
|
|
|
if (!chars) return parsed;
|
|
|
|
if ((flags & FLAG_WIDTH) && chars > width) chars = width;
|
|
|
|
if (!(flags & FLAG_DISCARD))
|
|
|
|
{
|
|
|
|
char* ptr;
|
|
|
|
if (flags & FLAG_ALLOC)
|
|
|
|
{
|
|
|
|
ptr = (char*)malloc(chars + 1);
|
|
|
|
if (!ptr) return parsed;
|
|
|
|
*va_arg(ap, char**) = ptr;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ptr = va_arg(ap, char*);
|
|
|
|
memcpy(ptr, str, chars);
|
|
|
|
ptr[chars] = 0;
|
|
|
|
}
|
|
|
|
str += chars;
|
|
|
|
parsed++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case 'c': {
|
|
|
|
if (strlen(str) < width) return parsed;
|
|
|
|
if (!(flags & FLAG_WIDTH)) width = 1;
|
|
|
|
if (!(flags & FLAG_DISCARD))
|
|
|
|
{
|
|
|
|
char* ptr;
|
|
|
|
if (flags & FLAG_ALLOC)
|
|
|
|
{
|
|
|
|
ptr = (char*)malloc(width);
|
|
|
|
if (!ptr) return parsed;
|
|
|
|
*va_arg(ap, char**) = ptr;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
ptr = va_arg(ap, char*);
|
|
|
|
memcpy(ptr, str, width);
|
|
|
|
}
|
|
|
|
str += width;
|
|
|
|
parsed++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default: {
|
|
|
|
fprintf(stderr, "vsscanf: unknown conversion specifier: %%%c\n", specifier);
|
|
|
|
return parsed;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return parsed;
|
|
|
|
}
|
|
|
|
}
|