203 lines
4.9 KiB
C
203 lines
4.9 KiB
C
#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;
|
|
}
|