libc+libluna: Move the scanf implementation from libc to libluna
This commit is contained in:
parent
cb0d5cb6a1
commit
e76a91d5d0
@ -20,7 +20,6 @@ set(SOURCES
|
|||||||
src/pwd.cpp
|
src/pwd.cpp
|
||||||
src/grp.cpp
|
src/grp.cpp
|
||||||
src/locale.cpp
|
src/locale.cpp
|
||||||
src/scanf.cpp
|
|
||||||
src/signal.cpp
|
src/signal.cpp
|
||||||
src/termios.cpp
|
src/termios.cpp
|
||||||
src/utime.cpp
|
src/utime.cpp
|
||||||
|
@ -1,263 +0,0 @@
|
|||||||
#include <errno.h>
|
|
||||||
#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)
|
|
||||||
#define FLAG_LONG (1 << 3)
|
|
||||||
#define FLAG_LONG_LONG (1 << 4)
|
|
||||||
#define FLAG_SHORT (1 << 5)
|
|
||||||
#define FLAG_CHAR (1 << 6)
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void parse_type(const char** format, int& flags)
|
|
||||||
{
|
|
||||||
// FIXME: Support %j (intmax_t/uintmax_t)
|
|
||||||
switch (**format)
|
|
||||||
{
|
|
||||||
case 'h':
|
|
||||||
flags |= FLAG_SHORT;
|
|
||||||
(*format)++;
|
|
||||||
if (**format == 'h')
|
|
||||||
{
|
|
||||||
flags |= FLAG_CHAR;
|
|
||||||
(*format)++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 'l':
|
|
||||||
flags |= FLAG_LONG;
|
|
||||||
(*format)++;
|
|
||||||
if (**format == 'l')
|
|
||||||
{
|
|
||||||
flags |= FLAG_LONG_LONG;
|
|
||||||
(*format)++;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 't':
|
|
||||||
flags |= (sizeof(ptrdiff_t) == sizeof(long)) ? FLAG_LONG : FLAG_LONG_LONG;
|
|
||||||
(*format)++;
|
|
||||||
break;
|
|
||||||
case 'z':
|
|
||||||
flags |= (sizeof(size_t) == sizeof(long)) ? FLAG_LONG : FLAG_LONG_LONG;
|
|
||||||
(*format)++;
|
|
||||||
break;
|
|
||||||
default: break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void write_parsed_signed_integer(ssize_t value, int flags, va_list ap)
|
|
||||||
{
|
|
||||||
if (flags & FLAG_LONG_LONG) *va_arg(ap, signed long long*) = (signed long long)value;
|
|
||||||
else if (flags & FLAG_LONG)
|
|
||||||
*va_arg(ap, signed long*) = (signed long)value;
|
|
||||||
else if (flags & FLAG_SHORT)
|
|
||||||
*va_arg(ap, signed int*) = (signed short)value;
|
|
||||||
else if (flags & FLAG_CHAR)
|
|
||||||
*va_arg(ap, signed int*) = (signed char)value;
|
|
||||||
else
|
|
||||||
*va_arg(ap, signed int*) = (signed int)value;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void write_parsed_unsigned_integer(size_t value, int flags, va_list ap)
|
|
||||||
{
|
|
||||||
if (flags & FLAG_LONG_LONG) *va_arg(ap, unsigned long long*) = (unsigned long long)value;
|
|
||||||
else if (flags & FLAG_LONG)
|
|
||||||
*va_arg(ap, unsigned long*) = (unsigned long)value;
|
|
||||||
else if (flags & FLAG_SHORT)
|
|
||||||
*va_arg(ap, unsigned int*) = (unsigned short)value;
|
|
||||||
else if (flags & FLAG_CHAR)
|
|
||||||
*va_arg(ap, unsigned int*) = (unsigned char)value;
|
|
||||||
else
|
|
||||||
*va_arg(ap, unsigned int*) = (unsigned int)value;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define WHITESPACE_CHARACTERS " \t\f\r\n\v"
|
|
||||||
|
|
||||||
static void skip_whitespace(const char** str)
|
|
||||||
{
|
|
||||||
*str += strspn(*str, WHITESPACE_CHARACTERS);
|
|
||||||
}
|
|
||||||
|
|
||||||
extern "C"
|
|
||||||
{
|
|
||||||
int vsscanf(const char* str, const char* format, va_list ap)
|
|
||||||
{
|
|
||||||
int parsed = 0;
|
|
||||||
const char* s = str; // Keep a pointer to the beginning of the string for %n
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
skip_whitespace(&format);
|
|
||||||
skip_whitespace(&str);
|
|
||||||
if (*str == 0) return parsed;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
format++;
|
|
||||||
if (*format == '%')
|
|
||||||
{
|
|
||||||
skip_whitespace(&str);
|
|
||||||
goto normal;
|
|
||||||
}
|
|
||||||
|
|
||||||
int flags = parse_flags(&format);
|
|
||||||
size_t width = parse_width(&format, flags);
|
|
||||||
parse_type(&format, flags);
|
|
||||||
char specifier = *format++;
|
|
||||||
if (!specifier) return parsed;
|
|
||||||
|
|
||||||
switch (specifier)
|
|
||||||
{
|
|
||||||
case 's': {
|
|
||||||
skip_whitespace(&str);
|
|
||||||
size_t chars = strcspn(str, WHITESPACE_CHARACTERS);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
case 'd': {
|
|
||||||
skip_whitespace(&str);
|
|
||||||
ssize_t value = scan_signed_integer(&str, 10);
|
|
||||||
if (!(flags & FLAG_DISCARD)) write_parsed_signed_integer(value, flags, ap);
|
|
||||||
parsed++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'i': {
|
|
||||||
skip_whitespace(&str);
|
|
||||||
ssize_t value = scan_signed_integer(&str, 0);
|
|
||||||
if (!(flags & FLAG_DISCARD)) write_parsed_signed_integer(value, flags, ap);
|
|
||||||
parsed++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'o': {
|
|
||||||
skip_whitespace(&str);
|
|
||||||
size_t value = scan_unsigned_integer(&str, 8);
|
|
||||||
if (!(flags & FLAG_DISCARD)) write_parsed_unsigned_integer(value, flags, ap);
|
|
||||||
parsed++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'u': {
|
|
||||||
skip_whitespace(&str);
|
|
||||||
size_t value = scan_unsigned_integer(&str, 10);
|
|
||||||
if (!(flags & FLAG_DISCARD)) write_parsed_unsigned_integer(value, flags, ap);
|
|
||||||
parsed++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'X':
|
|
||||||
case 'x': {
|
|
||||||
skip_whitespace(&str);
|
|
||||||
size_t value = scan_unsigned_integer(&str, 16);
|
|
||||||
if (!(flags & FLAG_DISCARD)) write_parsed_unsigned_integer(value, flags, ap);
|
|
||||||
parsed++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'p': {
|
|
||||||
skip_whitespace(&str);
|
|
||||||
size_t value = scan_unsigned_integer(&str, 16);
|
|
||||||
if (!(flags & FLAG_DISCARD)) *va_arg(ap, void**) = (void*)value;
|
|
||||||
parsed++;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 'n': {
|
|
||||||
if (!(flags & FLAG_DISCARD)) *va_arg(ap, int*) = (int)(str - s);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default: {
|
|
||||||
fprintf(stderr, "vsscanf: unknown conversion specifier: %%%c\n", specifier);
|
|
||||||
return parsed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return parsed;
|
|
||||||
}
|
|
||||||
}
|
|
@ -2,6 +2,7 @@
|
|||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <luna/Common.h>
|
#include <luna/Common.h>
|
||||||
#include <luna/Format.h>
|
#include <luna/Format.h>
|
||||||
|
#include <luna/Scanf.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -618,12 +619,17 @@ extern "C"
|
|||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int vsscanf(const char* str, const char* format, va_list ap)
|
||||||
|
{
|
||||||
|
return scanf_impl(str, format, ap);
|
||||||
|
}
|
||||||
|
|
||||||
int sscanf(const char* str, const char* format, ...)
|
int sscanf(const char* str, const char* format, ...)
|
||||||
{
|
{
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, format);
|
va_start(ap, format);
|
||||||
|
|
||||||
int rc = vsscanf(str, format, ap);
|
int rc = scanf_impl(str, format, ap);
|
||||||
|
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
@ -634,7 +640,7 @@ extern "C"
|
|||||||
{
|
{
|
||||||
char buf[BUFSIZ];
|
char buf[BUFSIZ];
|
||||||
if (!fgets(buf, sizeof(buf), stream)) return EOF;
|
if (!fgets(buf, sizeof(buf), stream)) return EOF;
|
||||||
return vsscanf(buf, format, ap);
|
return scanf_impl(buf, format, ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
int fscanf(FILE* stream, const char* format, ...)
|
int fscanf(FILE* stream, const char* format, ...)
|
||||||
|
@ -14,6 +14,7 @@ set(FREESTANDING_SOURCES
|
|||||||
src/SystemError.cpp
|
src/SystemError.cpp
|
||||||
src/Bitmap.cpp
|
src/Bitmap.cpp
|
||||||
src/Buffer.cpp
|
src/Buffer.cpp
|
||||||
|
src/Scanf.cpp
|
||||||
src/Stack.cpp
|
src/Stack.cpp
|
||||||
src/String.cpp
|
src/String.cpp
|
||||||
src/StringBuilder.cpp
|
src/StringBuilder.cpp
|
||||||
|
21
libluna/include/luna/Scanf.h
Normal file
21
libluna/include/luna/Scanf.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
/**
|
||||||
|
* @file Scanf.h
|
||||||
|
* @author apio (cloudapio.eu)
|
||||||
|
* @brief Scanf implementation.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2023, the Luna authors.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief scanf() implementation.
|
||||||
|
*
|
||||||
|
* @param str The string to read input from.
|
||||||
|
* @param format The format string.
|
||||||
|
* @param ap The variadic argument list.
|
||||||
|
* @return int The number of arguments read, or -1 if the string was empty.
|
||||||
|
*/
|
||||||
|
int scanf_impl(const char* str, const char* format, va_list ap);
|
270
libluna/src/Scanf.cpp
Normal file
270
libluna/src/Scanf.cpp
Normal file
@ -0,0 +1,270 @@
|
|||||||
|
/**
|
||||||
|
* @file Scanf.cpp
|
||||||
|
* @author apio (cloudapio.eu)
|
||||||
|
* @brief Scanf implementation.
|
||||||
|
*
|
||||||
|
* @copyright Copyright (c) 2023, the Luna authors.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <luna/CString.h>
|
||||||
|
#include <luna/CType.h>
|
||||||
|
#include <luna/DebugLog.h>
|
||||||
|
#include <luna/Heap.h>
|
||||||
|
#include <luna/NumberParsing.h>
|
||||||
|
#include <luna/SystemError.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#define FLAG_DISCARD (1 << 0)
|
||||||
|
#define FLAG_ALLOC (1 << 1)
|
||||||
|
#define FLAG_WIDTH (1 << 2)
|
||||||
|
#define FLAG_LONG (1 << 3)
|
||||||
|
#define FLAG_LONG_LONG (1 << 4)
|
||||||
|
#define FLAG_SHORT (1 << 5)
|
||||||
|
#define FLAG_CHAR (1 << 6)
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void parse_type(const char** format, int& flags)
|
||||||
|
{
|
||||||
|
// FIXME: Support %j (intmax_t/uintmax_t)
|
||||||
|
switch (**format)
|
||||||
|
{
|
||||||
|
case 'h':
|
||||||
|
flags |= FLAG_SHORT;
|
||||||
|
(*format)++;
|
||||||
|
if (**format == 'h')
|
||||||
|
{
|
||||||
|
flags |= FLAG_CHAR;
|
||||||
|
(*format)++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'l':
|
||||||
|
flags |= FLAG_LONG;
|
||||||
|
(*format)++;
|
||||||
|
if (**format == 'l')
|
||||||
|
{
|
||||||
|
flags |= FLAG_LONG_LONG;
|
||||||
|
(*format)++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 't':
|
||||||
|
flags |= (sizeof(ptrdiff_t) == sizeof(long)) ? FLAG_LONG : FLAG_LONG_LONG;
|
||||||
|
(*format)++;
|
||||||
|
break;
|
||||||
|
case 'z':
|
||||||
|
flags |= (sizeof(size_t) == sizeof(long)) ? FLAG_LONG : FLAG_LONG_LONG;
|
||||||
|
(*format)++;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_parsed_signed_integer(ssize_t value, int flags, va_list ap)
|
||||||
|
{
|
||||||
|
if (flags & FLAG_LONG_LONG) *va_arg(ap, signed long long*) = (signed long long)value;
|
||||||
|
else if (flags & FLAG_LONG)
|
||||||
|
*va_arg(ap, signed long*) = (signed long)value;
|
||||||
|
else if (flags & FLAG_SHORT)
|
||||||
|
*va_arg(ap, signed int*) = (signed short)value;
|
||||||
|
else if (flags & FLAG_CHAR)
|
||||||
|
*va_arg(ap, signed int*) = (signed char)value;
|
||||||
|
else
|
||||||
|
*va_arg(ap, signed int*) = (signed int)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void write_parsed_unsigned_integer(size_t value, int flags, va_list ap)
|
||||||
|
{
|
||||||
|
if (flags & FLAG_LONG_LONG) *va_arg(ap, unsigned long long*) = (unsigned long long)value;
|
||||||
|
else if (flags & FLAG_LONG)
|
||||||
|
*va_arg(ap, unsigned long*) = (unsigned long)value;
|
||||||
|
else if (flags & FLAG_SHORT)
|
||||||
|
*va_arg(ap, unsigned int*) = (unsigned short)value;
|
||||||
|
else if (flags & FLAG_CHAR)
|
||||||
|
*va_arg(ap, unsigned int*) = (unsigned char)value;
|
||||||
|
else
|
||||||
|
*va_arg(ap, unsigned int*) = (unsigned int)value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define WHITESPACE_CHARACTERS " \t\f\r\n\v"
|
||||||
|
|
||||||
|
static void skip_whitespace(const char** str)
|
||||||
|
{
|
||||||
|
*str += strspn(*str, WHITESPACE_CHARACTERS);
|
||||||
|
}
|
||||||
|
|
||||||
|
int scanf_impl(const char* str, const char* format, va_list ap)
|
||||||
|
{
|
||||||
|
int parsed = 0;
|
||||||
|
const char* s = str; // Keep a pointer to the beginning of the string for %n
|
||||||
|
|
||||||
|
if (*str == 0) return -1;
|
||||||
|
|
||||||
|
while (*format)
|
||||||
|
{
|
||||||
|
if (*format != '%')
|
||||||
|
{
|
||||||
|
normal:
|
||||||
|
if (!_isspace(*format))
|
||||||
|
{
|
||||||
|
if (*str != *format) return parsed;
|
||||||
|
str++;
|
||||||
|
format++;
|
||||||
|
if (*str == 0) return parsed;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
skip_whitespace(&format);
|
||||||
|
skip_whitespace(&str);
|
||||||
|
if (*str == 0) return parsed;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
format++;
|
||||||
|
if (*format == '%')
|
||||||
|
{
|
||||||
|
skip_whitespace(&str);
|
||||||
|
goto normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
int flags = parse_flags(&format);
|
||||||
|
size_t width = parse_width(&format, flags);
|
||||||
|
parse_type(&format, flags);
|
||||||
|
char specifier = *format++;
|
||||||
|
if (!specifier) return parsed;
|
||||||
|
|
||||||
|
switch (specifier)
|
||||||
|
{
|
||||||
|
case 's': {
|
||||||
|
skip_whitespace(&str);
|
||||||
|
size_t chars = strcspn(str, WHITESPACE_CHARACTERS);
|
||||||
|
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_impl(chars + 1).value_or(nullptr);
|
||||||
|
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_impl(width).value_or(nullptr);
|
||||||
|
if (!ptr) return parsed;
|
||||||
|
*va_arg(ap, char**) = ptr;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ptr = va_arg(ap, char*);
|
||||||
|
memcpy(ptr, str, width);
|
||||||
|
}
|
||||||
|
str += width;
|
||||||
|
parsed++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'd': {
|
||||||
|
skip_whitespace(&str);
|
||||||
|
ssize_t value = scan_signed_integer(&str, 10);
|
||||||
|
if (!(flags & FLAG_DISCARD)) write_parsed_signed_integer(value, flags, ap);
|
||||||
|
parsed++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'i': {
|
||||||
|
skip_whitespace(&str);
|
||||||
|
ssize_t value = scan_signed_integer(&str, 0);
|
||||||
|
if (!(flags & FLAG_DISCARD)) write_parsed_signed_integer(value, flags, ap);
|
||||||
|
parsed++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'o': {
|
||||||
|
skip_whitespace(&str);
|
||||||
|
size_t value = scan_unsigned_integer(&str, 8);
|
||||||
|
if (!(flags & FLAG_DISCARD)) write_parsed_unsigned_integer(value, flags, ap);
|
||||||
|
parsed++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'u': {
|
||||||
|
skip_whitespace(&str);
|
||||||
|
size_t value = scan_unsigned_integer(&str, 10);
|
||||||
|
if (!(flags & FLAG_DISCARD)) write_parsed_unsigned_integer(value, flags, ap);
|
||||||
|
parsed++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'X':
|
||||||
|
case 'x': {
|
||||||
|
skip_whitespace(&str);
|
||||||
|
size_t value = scan_unsigned_integer(&str, 16);
|
||||||
|
if (!(flags & FLAG_DISCARD)) write_parsed_unsigned_integer(value, flags, ap);
|
||||||
|
parsed++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'p': {
|
||||||
|
skip_whitespace(&str);
|
||||||
|
size_t value = scan_unsigned_integer(&str, 16);
|
||||||
|
if (!(flags & FLAG_DISCARD)) *va_arg(ap, void**) = (void*)value;
|
||||||
|
parsed++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'n': {
|
||||||
|
if (!(flags & FLAG_DISCARD)) *va_arg(ap, int*) = (int)(str - s);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
dbgln("vsscanf: unknown conversion specifier: %%%c\n", specifier);
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parsed;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user