Skip to content

Instantly share code, notes, and snippets.

@hiono
Last active August 29, 2015 14:02
Show Gist options
  • Save hiono/f8b9a9a9b980b2b2c402 to your computer and use it in GitHub Desktop.
Save hiono/f8b9a9a9b980b2b2c402 to your computer and use it in GitHub Desktop.
libyaml C-language wrapper
// -*- 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

  • libyaml
  • apach portable routine
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment