Squash commits for public release
This commit is contained in:
202
libs/libc/stdio/scanf.c
Normal file
202
libs/libc/stdio/scanf.c
Normal file
@@ -0,0 +1,202 @@
|
||||
#include "_internal.h"
|
||||
#include <ctype.h>
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/_structs.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static int _scanf_u32(_lookupch_callback lookupch, _getch_callback getch, void* callback_params, uint32_t* val)
|
||||
{
|
||||
int read = 0;
|
||||
uint32_t res = 0;
|
||||
while (isdigit(lookupch(callback_params))) {
|
||||
res *= 10;
|
||||
char ch = getch(callback_params);
|
||||
res += (ch - '0');
|
||||
read++;
|
||||
}
|
||||
*val = res;
|
||||
return read;
|
||||
}
|
||||
|
||||
static int _scanf_i32(_lookupch_callback lookupch, _getch_callback getch, void* callback_params, int* val)
|
||||
{
|
||||
int read = 0;
|
||||
bool negative = 0;
|
||||
if (lookupch(callback_params) == '-') {
|
||||
negative = true;
|
||||
getch(callback_params);
|
||||
read++;
|
||||
}
|
||||
|
||||
uint32_t tmp_u32;
|
||||
int read_imm = _scanf_u32(lookupch, getch, callback_params, &tmp_u32);
|
||||
if (!read_imm) {
|
||||
return 0;
|
||||
}
|
||||
read += read_imm;
|
||||
|
||||
int tmp_i32 = (int)tmp_u32;
|
||||
if (negative) {
|
||||
tmp_i32 = -tmp_i32;
|
||||
}
|
||||
*val = tmp_i32;
|
||||
|
||||
return read;
|
||||
}
|
||||
|
||||
static int _scanf_internal(const char* format, _lookupch_callback lookupch, _getch_callback getch, void* callback_params, va_list arg)
|
||||
{
|
||||
const char* p = format;
|
||||
int passed = 0;
|
||||
|
||||
while (*p) {
|
||||
int l_arg = 0;
|
||||
int h_arg = 0;
|
||||
while (isspace(*p)) {
|
||||
p++;
|
||||
}
|
||||
if (*p == '%' && *(p + 1)) {
|
||||
// Reading arguments
|
||||
parse_args:
|
||||
p++;
|
||||
switch (*p) {
|
||||
case 'l':
|
||||
l_arg++;
|
||||
if (*(p + 1)) {
|
||||
goto parse_args;
|
||||
}
|
||||
break;
|
||||
case 'h':
|
||||
h_arg++;
|
||||
if (*(p + 1)) {
|
||||
goto parse_args;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
while (isspace(lookupch(callback_params))) {
|
||||
getch(callback_params);
|
||||
passed++;
|
||||
}
|
||||
|
||||
switch (*p) {
|
||||
case 'i':
|
||||
case 'd':
|
||||
if (!l_arg) {
|
||||
int* value = va_arg(arg, int*);
|
||||
int read = _scanf_i32(lookupch, getch, callback_params, value);
|
||||
passed += read;
|
||||
}
|
||||
break;
|
||||
case 'u':
|
||||
if (!l_arg) {
|
||||
uint32_t* value = va_arg(arg, uint32_t*);
|
||||
int read = _scanf_u32(lookupch, getch, callback_params, value);
|
||||
passed += read;
|
||||
}
|
||||
break;
|
||||
case 's': {
|
||||
int rv = 0;
|
||||
char* value = va_arg(arg, char*);
|
||||
while (!isspace(lookupch(callback_params))) {
|
||||
char ch = getch(callback_params);
|
||||
value[rv++] = ch;
|
||||
passed++;
|
||||
}
|
||||
value[rv] = '\0';
|
||||
break;
|
||||
}
|
||||
}
|
||||
p++;
|
||||
} else {
|
||||
while (isspace(lookupch(callback_params))) {
|
||||
getch(callback_params);
|
||||
passed++;
|
||||
}
|
||||
if (lookupch(callback_params) != *p) {
|
||||
break;
|
||||
}
|
||||
p++;
|
||||
getch(callback_params);
|
||||
passed++;
|
||||
}
|
||||
}
|
||||
return passed;
|
||||
}
|
||||
|
||||
struct buffer_params {
|
||||
const char* buf;
|
||||
};
|
||||
typedef struct buffer_params buffer_params_t;
|
||||
|
||||
static int lookup_callback_buffer(void* callback_params)
|
||||
{
|
||||
buffer_params_t* bp = (buffer_params_t*)callback_params;
|
||||
if (!bp->buf) {
|
||||
return EOF;
|
||||
}
|
||||
return *bp->buf;
|
||||
}
|
||||
|
||||
static int getch_callback_buffer(void* callback_params)
|
||||
{
|
||||
buffer_params_t* bp = (buffer_params_t*)callback_params;
|
||||
if (!bp->buf) {
|
||||
return EOF;
|
||||
}
|
||||
char res = *bp->buf;
|
||||
bp->buf++;
|
||||
return res;
|
||||
}
|
||||
|
||||
int vsscanf(const char* buf, const char* format, va_list arg)
|
||||
{
|
||||
buffer_params_t bp = { .buf = buf };
|
||||
return _scanf_internal(format, lookup_callback_buffer, getch_callback_buffer, (void*)&bp, arg);
|
||||
}
|
||||
|
||||
static int lookup_callback_stream(void* callback_params)
|
||||
{
|
||||
FILE* file = (FILE*)callback_params;
|
||||
int res = fgetc(file);
|
||||
ungetc(res, file);
|
||||
return res;
|
||||
}
|
||||
|
||||
static int getch_callback_stream(void* callback_params)
|
||||
{
|
||||
FILE* file = (FILE*)callback_params;
|
||||
int res = fgetc(file);
|
||||
return res;
|
||||
}
|
||||
|
||||
int vfscanf(FILE* stream, const char* format, va_list arg)
|
||||
{
|
||||
return _scanf_internal(format, lookup_callback_stream, getch_callback_stream, (void*)stream, arg);
|
||||
}
|
||||
|
||||
int sscanf(const char* buf, const char* format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
int count = vsscanf(buf, format, ap);
|
||||
va_end(ap);
|
||||
return count;
|
||||
}
|
||||
|
||||
int scanf(const char* format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, format);
|
||||
int count = vfscanf(stdin, format, ap);
|
||||
va_end(ap);
|
||||
return count;
|
||||
}
|
||||
Reference in New Issue
Block a user