libyaml C-language wrapper
Need
- libyaml
- apach portable routine
| // -*- mode:c++; indent-tabs-mode: nil -*- | |
| // | |
| // yaml_parser.c | |
| // | |
| #include <stdint.h> | |
| #include <stdbool.h> | |
| #include <assert.h> | |
| #include <yaml.h> | |
| #include <apr_general.h> | |
| #include <apr_tables.h> | |
| #include <apr_strings.h> | |
| #include <apr_hash.h> | |
| #ifdef NDEBUG | |
| #define dprintf(...) ((void)0) | |
| #else | |
| #define dprintf(format, args ...) fprintf(stderr, "%s:%d: " format, __func__, __LINE__,## args) | |
| #define dprint_var(var,f) fprintf(stderr, #var "=%" #f "\n", var) | |
| #endif | |
| typedef enum yaml_object_type_e { | |
| eNULL, | |
| eSEQUENCE, | |
| eMAPPING, | |
| eVALUE, | |
| eEOL | |
| } yaml_object_type_t; | |
| typedef struct yaml_object_s { | |
| yaml_object_type_t type; | |
| apr_array_header_t *sequence; | |
| apr_hash_t *mapping; | |
| uint8_t *value; | |
| } yaml_object_t; | |
| static apr_array_header_t *parseSequence ( apr_pool_t * pool, | |
| yaml_parser_t * parser ); | |
| static apr_hash_t *parseMapping ( apr_pool_t * pool, yaml_parser_t * parser ); | |
| static uint8_t *parseValue ( apr_pool_t * pool, yaml_event_t * event ); | |
| #ifndef NDEBUG | |
| void debug_print ( uint8_t *, int, yaml_object_t * ); | |
| #endif | |
| yaml_object_t * | |
| yamlToObject ( apr_pool_t * pool, uint8_t * string ) | |
| { | |
| yaml_parser_t parser; | |
| yaml_parser_initialize ( &parser ); | |
| const char *chars = ( uint8_t * ) apr_pstrdup ( pool, string ); | |
| yaml_parser_set_input_string ( &parser, ( const uint8_t * ) chars, | |
| strlen ( chars ) ); | |
| while ( true ) { | |
| yaml_event_t event; | |
| yaml_object_t *ret = | |
| ( yaml_object_t * ) apr_palloc ( pool, sizeof ( yaml_object_t ) ); | |
| assert ( ret ); | |
| if ( !yaml_parser_parse ( &parser, &event ) ) { | |
| yaml_parser_delete ( &parser ); | |
| ret->type = eNULL; | |
| ret->mapping = ( void * ) NULL; | |
| ret->sequence = ( void * ) NULL; | |
| ret->value = ( void * ) NULL; | |
| return ret; | |
| } | |
| switch ( event.type ) { | |
| case YAML_SCALAR_EVENT: | |
| { | |
| uint8_t *value = parseValue ( pool, &event ); | |
| yaml_event_delete ( &event ); | |
| yaml_parser_delete ( &parser ); | |
| ret->type = eVALUE; | |
| ret->mapping = ( void * ) NULL; | |
| ret->sequence = ( void * ) NULL; | |
| ret->value = value; | |
| return ret; | |
| } | |
| case YAML_SEQUENCE_START_EVENT: | |
| { | |
| apr_array_header_t *sequenceValue = parseSequence ( pool, &parser ); | |
| yaml_event_delete ( &event ); | |
| yaml_parser_delete ( &parser ); | |
| ret->type = eSEQUENCE; | |
| ret->mapping = ( void * ) NULL; | |
| ret->sequence = sequenceValue; | |
| ret->value = ( void * ) NULL; | |
| return ret; | |
| } | |
| case YAML_MAPPING_START_EVENT: | |
| { | |
| apr_hash_t *mappingValue = parseMapping ( pool, &parser ); | |
| yaml_event_delete ( &event ); | |
| yaml_parser_delete ( &parser ); | |
| ret->type = eMAPPING; | |
| ret->mapping = mappingValue; | |
| ret->sequence = ( void * ) NULL; | |
| ret->value = ( void * ) NULL; | |
| return ret; | |
| } | |
| case YAML_STREAM_END_EVENT: | |
| { | |
| yaml_event_delete ( &event ); | |
| yaml_parser_delete ( &parser ); | |
| ret->type = eNULL; | |
| ret->mapping = ( void * ) NULL; | |
| ret->sequence = ( void * ) NULL; | |
| ret->value = ( void * ) NULL; | |
| return ret; | |
| } | |
| } | |
| yaml_event_delete ( &event ); | |
| } | |
| } | |
| yaml_object_t * | |
| searchObject ( apr_pool_t * pool, yaml_object_t * obj, uint8_t * key ) | |
| { | |
| #ifndef NDEBUG | |
| dprintf ( "%s: key=%s\n", __func__, key ); | |
| #endif | |
| while ( true ) { | |
| switch ( obj->type ) { | |
| case eNULL: | |
| #ifndef NDEBUG | |
| dprintf ( "type NULL: " ); | |
| #endif | |
| break; | |
| case eSEQUENCE: | |
| #ifndef NDEBUG | |
| dprintf ( "type SEQUENCE: " ); | |
| #endif | |
| { | |
| int j; | |
| apr_array_header_t *s = obj->sequence; | |
| for ( j = 0; j < s->nelts; j++ ) { | |
| yaml_object_t *v = | |
| *( yaml_object_t ** ) ( s->elts + ( s->elt_size * j ) ); | |
| if ( v->type == eVALUE ) { | |
| #ifndef NDEBUG | |
| dprintf ( "%s ", v->value ); | |
| #endif | |
| if ( apr_strnatcmp ( key, v->value ) == 0 ) | |
| return obj; | |
| } else { | |
| yaml_object_t *res; | |
| #ifndef NDEBUG | |
| if ( v->type == eMAPPING ) { | |
| dprintf ( "v is mapping\n" ); | |
| } else if ( v->type == eSEQUENCE ) { | |
| dprintf ( "v is sequence\n" ); | |
| } | |
| #endif | |
| res = searchObject ( pool, v, key ); | |
| if ( res ) | |
| return res; | |
| } | |
| } | |
| return NULL; | |
| } | |
| break; | |
| case eMAPPING: | |
| #ifndef NDEBUG | |
| dprintf ( "type MAPPING: " ); | |
| #endif | |
| { | |
| int j; | |
| apr_hash_t *m = obj->mapping; | |
| apr_hash_index_t *idx; | |
| for ( idx = apr_hash_first ( NULL, m ); idx; | |
| idx = apr_hash_next ( idx ) ) { | |
| const char *k; | |
| yaml_object_t *v, *res; | |
| apr_hash_this ( idx, ( const void ** ) &k, NULL, ( void ** ) &v ); | |
| #ifndef NDEBUG | |
| if ( v->type == eVALUE ) { | |
| dprintf ( "key=%s, val=%s\n", k, v->value ); | |
| } else if ( v->type == eMAPPING ) { | |
| dprintf ( "v is mapping\n" ); | |
| } else if ( v->type == eSEQUENCE ) { | |
| dprintf ( "v is sequence\n" ); | |
| } | |
| #endif | |
| if ( apr_strnatcmp ( key, k ) == 0 ) | |
| return obj; | |
| res = searchObject ( pool, v, key ); | |
| if ( res != ( void * ) NULL ) | |
| return res; | |
| } | |
| return NULL; | |
| } | |
| break; | |
| case eVALUE: | |
| #ifndef NDEBUG | |
| dprintf ( "type VALUE: " ); | |
| dprintf ( "%s\n", ( uint8_t * ) obj->value ); | |
| #endif | |
| if ( apr_strnatcmp ( key, obj->value ) == 0 ) | |
| return obj; | |
| else | |
| return NULL; | |
| case eEOL: | |
| #ifndef NDEBUG | |
| dprintf ( "type EOL: " ); | |
| #endif | |
| break; | |
| } | |
| } | |
| return NULL; | |
| } | |
| static apr_array_header_t * | |
| parseSequence ( apr_pool_t * pool, yaml_parser_t * parser ) | |
| { | |
| apr_array_header_t *sequence = | |
| apr_array_make ( pool, 0, sizeof ( yaml_object_t ) ); | |
| while ( true ) { | |
| yaml_event_t event; | |
| if ( !yaml_parser_parse ( parser, &event ) ) { | |
| return NULL; | |
| } | |
| switch ( event.type ) { | |
| case YAML_SCALAR_EVENT: | |
| { | |
| uint8_t *value = parseValue ( pool, &event ); | |
| assert ( value ); | |
| yaml_object_t *val = | |
| ( yaml_object_t * ) apr_palloc ( pool, sizeof ( yaml_object_t ) ); | |
| assert ( val ); | |
| val->type = eVALUE; | |
| val->mapping = ( void * ) NULL; | |
| val->sequence = ( void * ) NULL; | |
| val->value = value; | |
| *( yaml_object_t ** ) apr_array_push ( sequence ) = val; | |
| break; | |
| } | |
| case YAML_SEQUENCE_START_EVENT: | |
| { | |
| apr_array_header_t *sequenceValue = parseSequence ( pool, parser ); | |
| if ( !sequenceValue ) { | |
| yaml_event_delete ( &event ); | |
| return NULL; | |
| } | |
| yaml_object_t *val = | |
| ( yaml_object_t * ) apr_palloc ( pool, sizeof ( yaml_object_t ) ); | |
| assert ( val ); | |
| val->type = eSEQUENCE; | |
| val->mapping = ( void * ) NULL; | |
| val->sequence = sequenceValue; | |
| val->value = ( void * ) NULL; | |
| *( yaml_object_t ** ) apr_array_push ( sequence ) = val; | |
| break; | |
| } | |
| case YAML_SEQUENCE_END_EVENT: | |
| { | |
| yaml_event_delete ( &event ); | |
| return sequence; | |
| } | |
| case YAML_MAPPING_START_EVENT: | |
| { | |
| apr_hash_t *mappingValue = parseMapping ( pool, parser ); | |
| if ( !mappingValue ) { | |
| yaml_event_delete ( &event ); | |
| return NULL; | |
| } | |
| yaml_object_t *val = | |
| ( yaml_object_t * ) apr_palloc ( pool, sizeof ( yaml_object_t ) ); | |
| assert ( val ); | |
| val->type = eMAPPING; | |
| val->mapping = mappingValue; | |
| val->sequence = ( void * ) NULL; | |
| val->value = ( void * ) NULL; | |
| *( yaml_object_t ** ) apr_array_push ( sequence ) = val; | |
| break; | |
| } | |
| case YAML_STREAM_END_EVENT: | |
| { | |
| yaml_event_delete ( &event ); | |
| return NULL; | |
| } | |
| } | |
| yaml_event_delete ( &event ); | |
| } | |
| } | |
| static apr_hash_t * | |
| parseMapping ( apr_pool_t * pool, yaml_parser_t * parser ) | |
| { | |
| apr_hash_t *mapping = apr_hash_make ( pool ); | |
| uint8_t *key = ( void * ) NULL; | |
| while ( true ) { | |
| yaml_event_t event; | |
| if ( !yaml_parser_parse ( parser, &event ) ) { | |
| return NULL; | |
| } | |
| switch ( event.type ) { | |
| case YAML_SCALAR_EVENT: | |
| { | |
| uint8_t *value = parseValue ( pool, &event ); | |
| assert ( value ); | |
| if ( !key ) { | |
| key = value; | |
| } else { | |
| yaml_object_t *val = | |
| ( yaml_object_t * ) apr_palloc ( pool, sizeof ( yaml_object_t ) ); | |
| assert ( val ); | |
| val->type = eVALUE; | |
| val->value = value; | |
| apr_hash_set ( mapping, ( uint8_t * ) apr_pstrdup ( pool, key ), | |
| APR_HASH_KEY_STRING, ( void * ) val ); | |
| key = ( void * ) NULL; | |
| } | |
| break; | |
| } | |
| case YAML_SEQUENCE_START_EVENT: | |
| { | |
| apr_array_header_t *sequenceValue = parseSequence ( pool, parser ); | |
| if ( !sequenceValue ) { | |
| yaml_event_delete ( &event ); | |
| return NULL; | |
| } | |
| if ( key ) { | |
| yaml_object_t *val = | |
| ( yaml_object_t * ) apr_palloc ( pool, sizeof ( yaml_object_t ) ); | |
| assert ( val ); | |
| val->type = eSEQUENCE; | |
| val->sequence = sequenceValue; | |
| apr_hash_set ( mapping, ( uint8_t * ) apr_pstrdup ( pool, key ), | |
| APR_HASH_KEY_STRING, ( void * ) val ); | |
| key = ( void * ) NULL; | |
| } | |
| break; | |
| } | |
| case YAML_MAPPING_START_EVENT: | |
| { | |
| apr_hash_t *mappingValue = parseMapping ( pool, parser ); | |
| if ( !mappingValue ) { | |
| yaml_event_delete ( &event ); | |
| return NULL; | |
| } | |
| if ( key ) { | |
| yaml_object_t *val = | |
| ( yaml_object_t * ) apr_palloc ( pool, sizeof ( yaml_object_t ) ); | |
| assert ( val ); | |
| val->type = eMAPPING; | |
| val->mapping = mappingValue; | |
| apr_hash_set ( mapping, ( uint8_t * ) apr_pstrdup ( pool, key ), | |
| APR_HASH_KEY_STRING, ( void * ) val ); | |
| key = ( void * ) NULL; | |
| } | |
| break; | |
| } | |
| case YAML_MAPPING_END_EVENT: | |
| { | |
| yaml_event_delete ( &event ); | |
| return mapping; | |
| } | |
| case YAML_STREAM_END_EVENT: | |
| { | |
| yaml_event_delete ( &event ); | |
| return NULL; | |
| } | |
| } | |
| yaml_event_delete ( &event ); | |
| } | |
| } | |
| static uint8_t * | |
| parseValue ( apr_pool_t * pool, yaml_event_t * event ) | |
| { | |
| uint8_t *value = | |
| ( uint8_t * ) apr_pstrdup ( pool, event->data.scalar.value ); | |
| if ( event->data.scalar.quoted_implicit ) { | |
| return value; | |
| } | |
| // TODO: Add other type conversions. | |
| return value; | |
| } | |
| #ifndef NDEBUG | |
| debug_print ( uint8_t * func, int line, yaml_object_t * obj ) | |
| { | |
| if ( obj ) { | |
| fprintf ( stderr, "%s:%d = ", func, line ); | |
| switch ( obj->type ) { | |
| case eNULL: | |
| fprintf ( stderr, "type NULL: " ); | |
| break; | |
| case eSEQUENCE: | |
| fprintf ( stderr, "type SEQUENCE: " ); | |
| { | |
| int j; | |
| apr_array_header_t *s = obj->sequence; | |
| for ( j = 0; j < s->nelts; j++ ) { | |
| yaml_object_t *v = | |
| *( yaml_object_t ** ) ( s->elts + ( s->elt_size * j ) ); | |
| fprintf ( stderr, "%s ", v->value ); | |
| } | |
| fprintf ( stderr, "\n" ); | |
| fflush ( stdout ); | |
| } | |
| break; | |
| case eMAPPING: | |
| fprintf ( stderr, "type MAPPING: " ); | |
| { | |
| int j; | |
| apr_hash_t *m = obj->mapping; | |
| apr_hash_index_t *idx; | |
| for ( idx = apr_hash_first ( NULL, m ); idx; | |
| idx = apr_hash_next ( idx ) ) { | |
| const char *k; | |
| yaml_object_t *v; | |
| apr_hash_this ( idx, ( const void ** ) &k, NULL, ( void ** ) &v ); | |
| fprintf ( stderr, "key=%s, val=%s\n", k, v->value ); | |
| } | |
| fprintf ( stderr, "\n" ); | |
| fflush ( stdout ); | |
| } | |
| break; | |
| case eVALUE: | |
| fprintf ( stderr, "type VALUE: " ); | |
| { | |
| fprintf ( stderr, "%s\n", ( uint8_t * ) obj->value ); | |
| } | |
| break; | |
| case eEOL: | |
| fprintf ( stderr, "type EOL: " ); | |
| break; | |
| } | |
| } | |
| } | |
| #endif |
libyaml C-language wrapper
Need