#include #include #include #include #include "parseconfig.hfa" // *********************************** exceptions *********************************** EHM_VIRTUAL_TABLE(Validation_Failure, Validation_Failure_main_table); void ?{}( Validation_Failure & this, config_entry & entry ) with ( entry ) { this.virtual_table = &Validation_Failure_main_table; this.key = key; this.variable = variable; } void throwValidation_Failure( config_entry & entry ) { Validation_Failure exc = { entry }; } // *********************************** main code *********************************** struct KVPairs { int size, max_size; * [ char *, char * ] data; }; void ?{}( KVPairs & kvp ) with ( kvp ) { // default constructor size = 0; max_size = 0; data = 0p; } void ?{}( KVPairs & kvp, int size ) { // initialization kvp.[ size, max_size ] = [ 0, size ]; kvp.data = alloc( size ); } /* void ?{}( KVPairs & kvp, KVPairs val ) with( val ) { // copy, deep kvp.[ size, max_size ] = [ size, max_size ]; kvp.data = alloc( size, data ); } */ void ^?{}( KVPairs & kvp ) with ( kvp ) { // destructor free( data ); size = 0; max_size = 0; data = 0p; } void add_kv_pair( KVPairs & kv_pairs, char * k, char * v ) with ( kv_pairs ) { if ( size == max_size ) { max_size *= 2; data = resize( data, max_size ); } data[size] = [ k, v ]; ++size; } struct StringBuilder { int size, max_size; * char string; }; void ?{}( StringBuilder & sb ) with ( sb ) { // default constructor size = 1; max_size = 1; string = alloc( 1 ); string[0] = '\0'; } void ?{}( StringBuilder & sb, int size ) { // initialization sb.[ size, max_size ] = [ 1, size+1 ]; sb.string = alloc( size ); sb.string[0] = '\0'; } void ^?{}( StringBuilder & sb ) with ( sb ) { // destructor free( string ); size = 0; max_size = 0; string = 0p; } void add_char( StringBuilder & sb, char c ) with ( sb ) { if ( size == max_size ) { max_size *= 2; string = resize( string, max_size ); } string[size-1] = c; string[size] = '\0'; ++size; } bool comments( ifstream & in, char * name ) { StringBuilder sb; char c; while () { in | c; add_char( sb, c ); if ( fail( in ) ) { name = alloc( sb.size ); strcpy( name, sb.string ); return true; } if ( c != '#' ) break; in | nl; // ignore remainder of line } // for name = alloc( sb.size ); strcpy( name, sb.string ); return false; } // comments // Parse configuration from a file formatted in shell style KVPairs & parse_tabular_config_format( const char * config_file, size_t num_entries ) { // * KVPairs kv_pairs; KVPairs kv_pairs = { num_entries }; ifstream in; try { open( in, config_file ); // open the configuration file for input while () { // * char key; // * char value; // if ( comments( in, key ) ) break; // eof ? // THE CODE BELOW IS TEMPORARY, TO TRY AND GET SOMETHING WORKING // Right now doesn't handle duplicate keys. Should use hashmap for that char c; StringBuilder key_sb; StringBuilder value_sb; // Doesn't handle comments while () { in | c; if ( c == ' ' ) { while ( c == ' ' ) in | c; } else { add_char( key_sb, c ); } } * char key = alloc( key_sb.size ); strcpy( key, key_sb.string ); // Doesn't handle comments while () { in | c; if ( c == ' ' || c == '\n' ) break; add_char( value_sb, c ); } * char value = alloc( value_sb.size ); strcpy( value, value_sb.string ); add_kv_pair( kv_pairs, key, value ); if ( fail( in ) ) break; in | nl; // ignore remainder of line } // for } catch( Open_Failure * ex; ex->istream == &in ) { ^kv_pairs{}; exit | "Error: could not open input file \"" | config_file | "\""; } // try close( in ); return kv_pairs; } // Parse configuration values from intermediate format void parse_config( const char * config_file, config_entry entries[], size_t num_entries ) { KVPairs kv_pairs = parse_tabular_config_format( config_file, num_entries ); int entries_so_far = 0; for ( i; kv_pairs.size ) { if ( entries_so_far == num_entries ) break; char * src_key, * src_value; [ src_key, src_value ] = kv_pairs.data[i]; for ( j; num_entries ) { if ( strcmp( src_key, entries[j].key ) != 0 ) continue; if ( entries[j].parse( src_value, entries[j].variable ) ) { ++entries_so_far; // Validate the parsed data, if necessary if ( entries[j].validate != (bool (*)(void *))0p ) { if ( !entries[j].validate( entries[j].variable ) ) throwValidation_Failure( entries[j] ); } break; } serr | "Value '" | src_value | "' for key '" | src_key | "' could not be parsed"; } } } // processConfigFile // *********************************** validation *********************************** forall(T | Relational( T )) bool is_nonnegative( T & value ) { T zero_val = 0; return value >= zero_val; } forall(T | Relational( T )) bool is_positive( T & value ) { T zero_val = 0; return value > zero_val; } forall(T | Relational( T )) bool is_nonpositive( T & value ) { T zero_val = 0; return value <= zero_val; } forall(T | Relational( T )) bool is_negative( T & value ) { T zero_val = 0; return value < zero_val; } // Local Variables: // // tab-width: 4 // // compile-command: "cfa parseconfig.cfa" // // End: //