#include #include #include #include #include "parseconfig.hfa" // *********************************** exceptions *********************************** static vtable(Parse_Failure) Parse_Failure_vt; void ?{}( Parse_Failure & this ) with ( this ) { virtual_table = &Parse_Failure_vt; } static vtable(Validation_Failure) Validation_Failure_vt; void ?{}( Validation_Failure & this ) with ( this ) { virtual_table = &Validation_Failure_vt; } // *********************************** main code *********************************** struct KVPairs { size_t size, max_size; * [ char *, char * ] data; }; void ?{}( KVPairs & kvp ) with ( kvp ) { // default constructor size = 0; max_size = 0; data = 0p; } void ?{}( KVPairs & kvp, size_t size ) { // initialization kvp.[ size, max_size ] = [ 0, size ]; kvp.data = alloc( size ); } void ^?{}( KVPairs & kvp ) with ( kvp ) { // destructor for ( i; size ) free( data[i] ); free( data ); size = 0; max_size = 0; data = 0p; } void add_kv_pair( KVPairs & kv_pairs, char * k, char * v ) with ( kv_pairs ) { if ( max_size == 0 ) { max_size = 1; data = alloc( max_size ); } else if ( size == max_size ) { max_size *= 2; data = alloc( max_size, data`realloc ); } data[size].0 = alloc( strlen( k ) ); data[size].1 = alloc( strlen( v ) ); strcpy( data[size].0, k ); strcpy( data[size].1, v ); ++size; } bool comments( ifstream & in, char name[] ) { while () { in | name; if ( eof( in ) ) return true; if ( name[0] != '#' ) return false; in | nl; // ignore remainder of line } // while } // 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 = new( num_entries ); ifstream in; try { open( in, config_file ); // open the configuration file for input char key[64]; char value[256]; while () { // parameter names can appear in any order // Must add check to see if already read in a key-value pair, // once we switch to using hash table as intermediate storage if ( comments( in, key ) ) break; // eof ? in | value; add_kv_pair( *kv_pairs, key, value ); if ( eof( in ) ) break; in | nl; // ignore remainder of line } // for } catch( Open_Failure * ex; ex->istream == &in ) { delete( kv_pairs ); serr | "Error: could not open input file '" | config_file | "'"; throw *ex; } // 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, config_format format ) { KVPairs * kv_pairs = 0p; choose ( format ) { case TABULAR_CONFIG: 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 ) ) { delete( kv_pairs ); serr | "Error: value '" | src_value | "' for key '" | src_key | "' could not be parsed"; throw (Parse_Failure){}; } // Validate the parsed data, if necessary if ( entries[j].validate != (bool (*)(void *))0p && !entries[j].validate( entries[j].variable ) ) { delete( kv_pairs ); serr | "Error: config value at key '" | entries[j].key | "' did not pass validation"; throw (Validation_Failure){}; } ++entries_so_far; break; } } delete( kv_pairs ); } // 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: //