parent
e31b804fdc
commit
12292c201e
@ -0,0 +1,3 @@
|
||||
[submodule "src/json"]
|
||||
path = src/json
|
||||
url = https://teknomunk@gitea.polaris-1.work/teknomunk/json.git
|
@ -0,0 +1 @@
|
||||
Subproject commit 5dd89c8024b5ac0a3eb3675cc3871799e9c9c010
|
@ -1,463 +0,0 @@
|
||||
#include "json.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
enum parser_state
|
||||
{
|
||||
ps_object_expect_key = 1,
|
||||
ps_object_expect_comma_then_key = 2,
|
||||
ps_object_expect_value = 3,
|
||||
|
||||
ps_array_expect_value = 11,
|
||||
ps_array_expect_comma_then_value = 12,
|
||||
|
||||
ps_expect_value = 20,
|
||||
};
|
||||
|
||||
struct json_pull_parser
|
||||
{
|
||||
FILE* f;
|
||||
int curr_state;
|
||||
};
|
||||
|
||||
static void eat_whitespace( FILE* f )
|
||||
{
|
||||
for(;;) {
|
||||
int i = fgetc(f);
|
||||
|
||||
if( i == EOF ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if( !isspace(i) ) {
|
||||
ungetc(i,f);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool json_pull_parser_handle_array_comma( struct json_pull_parser* jpp )
|
||||
{
|
||||
eat_whitespace(jpp->f);
|
||||
|
||||
switch( jpp->curr_state ) {
|
||||
case ps_array_expect_comma_then_value:
|
||||
break;
|
||||
case ps_object_expect_key:
|
||||
case ps_object_expect_comma_then_key:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
||||
int i = fgetc(jpp->f);
|
||||
if( i == ']' ) {
|
||||
ungetc(i,jpp->f);
|
||||
return true;
|
||||
}
|
||||
if( i != ',' ) {
|
||||
printf( "expecting comma, got %c(%d)\n", (char)i, i );
|
||||
return false;
|
||||
}
|
||||
|
||||
eat_whitespace(jpp->f);
|
||||
|
||||
return true;
|
||||
}
|
||||
static bool finish_value_read( struct json_pull_parser* jpp, bool result )
|
||||
{
|
||||
switch( jpp->curr_state ) {
|
||||
case ps_object_expect_value:
|
||||
jpp->curr_state = ps_object_expect_comma_then_key;
|
||||
break;
|
||||
case ps_array_expect_value:
|
||||
jpp->curr_state = ps_array_expect_comma_then_value;
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
struct json_pull_parser* json_pull_parser_new( FILE* f )
|
||||
{
|
||||
if( !f ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct json_pull_parser* jpp = (struct json_pull_parser*)malloc( sizeof( struct json_pull_parser ) );
|
||||
if( !jpp ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jpp->f = f;
|
||||
jpp->curr_state = ps_expect_value;
|
||||
|
||||
return jpp;
|
||||
}
|
||||
void json_pull_parser_release( struct json_pull_parser* jpp )
|
||||
{
|
||||
free(jpp);
|
||||
}
|
||||
|
||||
bool json_pull_parser_begin_object( struct json_pull_parser* jpp, int* save )
|
||||
{
|
||||
if( !json_pull_parser_handle_array_comma( jpp ) ) {
|
||||
return false;
|
||||
}
|
||||
*save = jpp->curr_state;
|
||||
|
||||
FILE* f = jpp->f;
|
||||
|
||||
eat_whitespace(f);
|
||||
|
||||
int i = fgetc( f );
|
||||
if( i != '{' ) {
|
||||
ungetc( i, jpp->f );
|
||||
return false;
|
||||
}
|
||||
|
||||
jpp->curr_state = ps_object_expect_key;
|
||||
|
||||
return true;
|
||||
}
|
||||
bool json_pull_parser_end_object( struct json_pull_parser* jpp, int* save )
|
||||
{
|
||||
eat_whitespace( jpp->f );
|
||||
|
||||
int i = fgetc( jpp->f );
|
||||
if( i != '}' ) {
|
||||
printf( "Missing }, got %c (%d)\n", (char)i, i );
|
||||
return false;
|
||||
}
|
||||
jpp->curr_state = *save;
|
||||
return finish_value_read( jpp, true );
|
||||
}
|
||||
|
||||
bool json_pull_parser_begin_array( struct json_pull_parser* jpp, int* save )
|
||||
{
|
||||
*save = jpp->curr_state;
|
||||
|
||||
eat_whitespace(jpp->f);
|
||||
|
||||
int i = fgetc(jpp->f);
|
||||
if( i != '[' ) {
|
||||
printf( "Unable to start array, i=%c(%d)\n", (char)i, i );
|
||||
ungetc( i, jpp->f );
|
||||
return false;
|
||||
}
|
||||
|
||||
jpp->curr_state = ps_array_expect_value;
|
||||
|
||||
return true;
|
||||
}
|
||||
bool json_pull_parser_end_array( struct json_pull_parser* jpp, int* save )
|
||||
{
|
||||
eat_whitespace(jpp->f);
|
||||
|
||||
int i = fgetc( jpp->f );
|
||||
if( i != ']' ) {
|
||||
ungetc(i,jpp->f);
|
||||
return false;
|
||||
}
|
||||
jpp->curr_state = *save;
|
||||
return finish_value_read( jpp, true );
|
||||
}
|
||||
static char* json_pull_parser_raw_read_string( struct json_pull_parser* jpp )
|
||||
{
|
||||
eat_whitespace(jpp->f);
|
||||
|
||||
int c = fgetc(jpp->f);
|
||||
if( c != '"' ) {
|
||||
ungetc(c,jpp->f);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* result = (char*)malloc(17);
|
||||
if( !result ) {
|
||||
return NULL;
|
||||
}
|
||||
size_t alloc_size = 17;
|
||||
size_t length = 0;
|
||||
result[0] = '\0';
|
||||
|
||||
bool done = false;
|
||||
while(!done) {
|
||||
c = fgetc(jpp->f);
|
||||
if( c == EOF ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char ch;
|
||||
if( c == '"' ) {
|
||||
done = true;
|
||||
break;
|
||||
} else if( c == '\\' ) {
|
||||
printf( "TODO: handle string escape sequences\n" );
|
||||
exit(1);
|
||||
} else {
|
||||
ch = (char)c;
|
||||
}
|
||||
|
||||
if( length + 1 >= alloc_size ) {
|
||||
result = realloc( result, alloc_size + 16 );
|
||||
alloc_size += 16;
|
||||
}
|
||||
result[length] = ch;
|
||||
result[length+1] = '\0';
|
||||
length += 1;
|
||||
}
|
||||
|
||||
finish_value_read( jpp, true );
|
||||
return result;
|
||||
}
|
||||
char* json_pull_parser_read_object_key ( struct json_pull_parser* jpp )
|
||||
{
|
||||
if( jpp->curr_state == ps_object_expect_comma_then_key ) {
|
||||
eat_whitespace(jpp->f);
|
||||
int i = fgetc(jpp->f);
|
||||
if( i != ',' ) {
|
||||
ungetc( i, jpp->f );
|
||||
return NULL;
|
||||
}
|
||||
} else if( jpp->curr_state != ps_object_expect_key ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char* str = json_pull_parser_raw_read_string( jpp );
|
||||
if( !str ) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
eat_whitespace(jpp->f);
|
||||
int i = fgetc( jpp->f );
|
||||
if( i != ':' ) {
|
||||
free(str);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jpp->curr_state = ps_object_expect_value;
|
||||
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
char* json_pull_parser_read_string( struct json_pull_parser* jpp )
|
||||
{
|
||||
if( !json_pull_parser_handle_array_comma( jpp ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return json_pull_parser_raw_read_string(jpp);
|
||||
}
|
||||
|
||||
enum number_type {
|
||||
nt_no_result = 0,
|
||||
nt_integer = 1,
|
||||
nt_float = 2,
|
||||
};
|
||||
|
||||
int json_pull_parser_read_number( struct json_pull_parser* jpp, int* i, float* f )
|
||||
{
|
||||
eat_whitespace(jpp->f);
|
||||
|
||||
char buffer[50];
|
||||
char* pos = &buffer[0];
|
||||
bool must_be_float = false;
|
||||
|
||||
int c = fgetc(jpp->f);
|
||||
if( c == '-' ) {
|
||||
*pos = '-';
|
||||
pos += 1;
|
||||
c = fgetc(jpp->f);
|
||||
}
|
||||
if( c == EOF ) { return nt_no_result; }
|
||||
|
||||
if( c == '0' ) {
|
||||
*pos = c;
|
||||
pos += 1;
|
||||
} else if( c >= '1' && c <= '9' ) {
|
||||
*pos = c;
|
||||
pos += 1;
|
||||
for(;;) {
|
||||
c = fgetc(jpp->f);
|
||||
if( c == EOF ) { return nt_no_result; }
|
||||
|
||||
if( c >= '0' && c <= '9' ) {
|
||||
*pos = c;
|
||||
pos += 1;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ungetc(c,jpp->f);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
if( c == '.' ) {
|
||||
// fractional part
|
||||
for(;;) {
|
||||
c = fgetc(jpp->f);
|
||||
if( c == '0' ) {
|
||||
} else if( c >= '1' && c <= '9' ) {
|
||||
must_be_float = true;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
|
||||
*pos = c;
|
||||
++pos;
|
||||
}
|
||||
}
|
||||
|
||||
if( c == 'e' || c == 'E' ) {
|
||||
bool negative_exponent = false;
|
||||
// exponent part
|
||||
c = fgetc( jpp->f );
|
||||
if( c == '-' ) {
|
||||
negative_exponent = true;
|
||||
c = fgetc(jpp->f);
|
||||
} else if( c == '+' ) {
|
||||
c = fgetc(jpp->f);
|
||||
}
|
||||
|
||||
for(;;) {
|
||||
if( c >= '1' && c <= '9' ) {
|
||||
if( negative_exponent ) {
|
||||
must_be_float = true;
|
||||
}
|
||||
*pos = c;
|
||||
pos += 1;
|
||||
|
||||
c = fgetc(jpp->f);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ungetc( c, jpp->f );
|
||||
int res = nt_no_result;
|
||||
|
||||
*pos = '\0';
|
||||
|
||||
if( pos == &buffer[0] ) {
|
||||
return nt_no_result;
|
||||
}
|
||||
|
||||
if( f ) {
|
||||
char* rem = NULL;
|
||||
*f = strtof( buffer, &rem );
|
||||
if( rem != pos ) {
|
||||
return nt_no_result;
|
||||
}
|
||||
|
||||
if( i && !must_be_float ) {
|
||||
*i = *f;
|
||||
res = nt_integer;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
res = nt_float;
|
||||
goto finish;
|
||||
} else if( must_be_float ) {
|
||||
return nt_no_result;
|
||||
}
|
||||
|
||||
if( i ) {
|
||||
char* rem = NULL;
|
||||
*i = strtol( buffer, &rem, 10 );
|
||||
if( rem != pos ) {
|
||||
return nt_no_result;
|
||||
}
|
||||
|
||||
res = nt_integer;
|
||||
goto finish;
|
||||
}
|
||||
|
||||
return nt_no_result;
|
||||
|
||||
finish:
|
||||
|
||||
return finish_value_read( jpp, res );
|
||||
}
|
||||
bool json_pull_parser_read_int( struct json_pull_parser* jpp, int* i )
|
||||
{
|
||||
return json_pull_parser_read_number(jpp,i,NULL) == nt_integer;
|
||||
}
|
||||
bool json_pull_parser_read_float( struct json_pull_parser* jpp, float* f )
|
||||
{
|
||||
return json_pull_parser_read_number(jpp,NULL,f) == nt_float;
|
||||
}
|
||||
bool json_pull_parser_read_null( struct json_pull_parser* jpp )
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool json_pull_parser_read_value( struct json_pull_parser* jpp )
|
||||
{
|
||||
if( json_pull_parser_read_null(jpp) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if( !json_pull_parser_handle_array_comma( jpp ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int i;
|
||||
float f;
|
||||
if( json_pull_parser_read_number(jpp,&i,&f) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
char* s;
|
||||
if( s = json_pull_parser_read_string(jpp) ) {
|
||||
free(s);
|
||||
return true;
|
||||
}
|
||||
|
||||
if( json_pull_parser_begin_object(jpp,&i) ) {
|
||||
while( s = json_pull_parser_read_object_key(jpp) ) {
|
||||
free(s);
|
||||
|
||||
if( !json_pull_parser_read_value(jpp) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return json_pull_parser_end_object(jpp,&i);
|
||||
}
|
||||
if( json_pull_parser_begin_array(jpp,&i) ) {
|
||||
for(;;) {
|
||||
if( json_pull_parser_end_array(jpp,&i) ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if( !json_pull_parser_read_value(jpp) ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void json_pull_parser_debug_dump( struct json_pull_parser* jpp )
|
||||
{
|
||||
printf( "state = %d\n", jpp->curr_state );
|
||||
|
||||
FILE* f = jpp->f;
|
||||
|
||||
for(;;) {
|
||||
int c = fgetc(f);
|
||||
if( c == EOF ) {
|
||||
return;
|
||||
}
|
||||
|
||||
printf( "%c", (char)c );
|
||||
}
|
||||
}
|
||||
|
@ -1,26 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
struct json_pull_parser;
|
||||
|
||||
struct json_pull_parser* json_pull_parser_new( FILE* f );
|
||||
|
||||
void json_pull_parser_release ( struct json_pull_parser* jpp );
|
||||
|
||||
bool json_pull_parser_begin_object ( struct json_pull_parser* jpp, int* save );
|
||||
bool json_pull_parser_end_object ( struct json_pull_parser* jpp, int* save );
|
||||
|
||||
bool json_pull_parser_begin_array ( struct json_pull_parser* jpp, int* save );
|
||||
bool json_pull_parser_end_array ( struct json_pull_parser* jpp, int* save );
|
||||
|
||||
char* json_pull_parser_read_object_key ( struct json_pull_parser* jpp );
|
||||
char* json_pull_parser_read_string ( struct json_pull_parser* jpp );
|
||||
bool json_pull_parser_read_int ( struct json_pull_parser* jpp, int* i );
|
||||
bool json_pull_parser_read_float ( struct json_pull_parser* jpp, float* i );
|
||||
bool json_pull_parser_read_null ( struct json_pull_parser* jpp );
|
||||
bool json_pull_parser_read_value ( struct json_pull_parser* jpp );
|
||||
|
||||
void json_pull_parser_debug_dump ( struct json_pull_parser* jpp );
|
||||
|
Loading…
Reference in new issue