stmbl/shared/scanf.c

280 lines
7.4 KiB
C

//
// scanf.c
// test
//
// Created by crinq on 05.12.13.
// Copyright (c) 2013 Rene Hopf. All rights reserved.
//
#include "scanf.h"
int sscanf_(const char *buf, const char *format, ...){
int ret = 0;
va_list arg;
va_start(arg, format);
ret = vfsscanf_(buf, format, arg);
va_end(arg);
return(ret);
}
int isBinDigit(char c){
return(c == '0' || c == '1');
}
int isChar(char c){
return((c <= 'Z' && c >= 'A') || (c <= 'z' && c >= 'a') || isDecDigit(c));
}
int isNameChar(char c){
return(isChar(c) || c == '_' || c == '-' || c == '.');
}
int isDecDigit(char c){
return(c >= '0' && c <= '9');
}
int isHexDigit(char c){
return((c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'));
}
int isWhitespace(char c){
return(c == ' ' || c == '\t');
}
int vfsscanf_(const char *buf, const char *format, va_list arg){
int buffer_pos = 0;
int format_pos = 0;
int string_pos = 0;
int ret = 0;
int found = 0;
int *i;
float *f;
char *c;
int invert;
float tf;
int state = 0; // 0 = last char = normal char
// 1 = last char = '%'
// 2 = last char = '\'
while(format[format_pos]){
found = 0;
switch(state){
case 0:
switch(format[format_pos]){
case '%':
state = 1;
format_pos++;
continue;
break;
case '\'':
state = 2;
format_pos++;
continue;
break;
case ' ': // parse whithespaces
while(isWhitespace(buf[buffer_pos])){
buffer_pos++;
found++;
}
found++;
break;
default:
if(format[format_pos] != buf[buffer_pos++]){
return(ret);
}
found++;
}
break;
case 1:
switch(format[format_pos]){
case '%':
if(buf[buffer_pos++] != '%'){
return(ret);
}
found++;
break;
case 'c':
c = va_arg(arg, char *);
*c = buf[buffer_pos++];
found++;
break;
case 's':
string_pos = 0;
c = va_arg(arg, char *);
//while(isChar(buf[buffer_pos])){
while(!isWhitespace(buf[buffer_pos])){
c[string_pos] = buf[buffer_pos++];
string_pos++;
c[string_pos] = '\0';
found++;
}
break;
case 'N':
string_pos = 0;
c = va_arg(arg, char *);
//while(isChar(buf[buffer_pos])){
while(isNameChar(buf[buffer_pos])){
c[string_pos] = buf[buffer_pos++];
string_pos++;
c[string_pos] = '\0';
found++;
}
break;
case 'i':
i = va_arg(arg, int *);
*i = 0;
invert = 1;
if(buf[buffer_pos] == '-'){
invert = -1;
buffer_pos++;
}
else if(buf[buffer_pos] == '+'){
buffer_pos++;
}
while(isDecDigit(buf[buffer_pos])){
*i *= 10;
*i += buf[buffer_pos++] - '0';
found++;
}
*i *= invert;
break;
case 'b':
i = va_arg(arg, int *);
*i = 0;
invert = 1;
if(buf[buffer_pos] == '-'){
invert = -1;
buffer_pos++;
}
else if(buf[buffer_pos] == '+'){
buffer_pos++;
}
if(!(buf[buffer_pos] == 'b' || buf[buffer_pos] == 'B')){
return(ret);
}
buffer_pos++;
while(isBinDigit(buf[buffer_pos])){
*i *= 2;
*i += buf[buffer_pos++] - '0';
found++;
}
*i *= invert;
break;
case 'h':
i = va_arg(arg, int *);
*i = 0;
invert = 1;
if(buf[buffer_pos] == '-'){
invert = -1;
buffer_pos++;
}
else if(buf[buffer_pos] == '+'){
buffer_pos++;
}
if(buf[buffer_pos++] != '0'){
return(ret);
}
if(buf[buffer_pos++] != 'x'){
return(ret);
}
while(isHexDigit(buf[buffer_pos])){
*i *= 16;
if(buf[buffer_pos] < 'A'){
*i += buf[buffer_pos++] - '0';
}
else if(buf[buffer_pos] < 'a'){
*i += buf[buffer_pos++] - 'A' + 10;
}
else{
*i += buf[buffer_pos++] - 'a' + 10;
}
found++;
}
*i *= invert;
break;
case 'f':
f = va_arg(arg, float *);
*f = 0;
tf = 10;
invert = 1;
if(buf[buffer_pos] == '-'){
invert = -1;
buffer_pos++;
}
else if(buf[buffer_pos] == '+'){
buffer_pos++;
}
while(isDecDigit(buf[buffer_pos])){
*f *= 10;
*f += buf[buffer_pos++] - '0';
found++;
}
if(buf[buffer_pos] == '.'){
buffer_pos++;
while(isDecDigit(buf[buffer_pos])){
*f += (buf[buffer_pos++] - '0') / tf;
tf *= 10;
found++;
}
}
*f *= invert;
break;
default:
return(ret);
break;
}
state = 0;
break;
case 2:
switch(format[format_pos]){
case '\'':
if(buf[buffer_pos++] != '\''){
return(ret);
}
found++;
break;
case 'n':
if(buf[buffer_pos++] != '\n'){
return(ret);
}
found++;
break;
default:
return(ret);
break;
}
state = 0;
break;
default:
break;
}
format_pos++;
if(!found){
return(ret);
}
ret++;
}
return(ret);
}