00001 #include <eh_utils.h>
00002
00003 CLASS( Eh_key_file )
00004 {
00005 GHashTable* t;
00006 GList* l;
00007 };
00008
00009 GQuark
00010 eh_key_file_error_quark( void )
00011 {
00012 return g_quark_from_static_string( "eh-key-file-error-quark" );
00013 }
00014
00026 void destroy_hash_table_list( gpointer key , gpointer value , gpointer user_data )
00027 {
00028 GList* l;
00029 for ( l=value ; l ; l = l->next )
00030 eh_symbol_table_destroy( (Eh_symbol_table)(l->data) );
00031 g_list_free( value );
00032 }
00033
00044 void dup_key( gpointer key , gpointer value , gpointer user_data )
00045 {
00046 gchar** s = (gchar**)(user_data);
00047 gchar* new_str;
00048
00049 if ( (*s)[0] == '\0' )
00050 new_str = g_strdup( key );
00051 else
00052 new_str = g_strjoin( "\n" , (*s) , key , NULL );
00053
00054 eh_free( *s );
00055 (*s) = new_str;
00056
00057 }
00058
00069 gchar** eh_key_file_list_to_array( GList* l , gpointer key )
00070 {
00071 gchar** ans;
00072 guint len = g_list_length( l );
00073 guint i;
00074
00075 ans = g_new( gchar* , len+1 );
00076 for ( i=0 ; l ; i++, l=l->next )
00077 ans[i] = g_strdup( eh_symbol_table_lookup(l->data,key) );
00078 ans[len] = NULL;
00079
00080 return ans;
00081 }
00082
00096 Eh_symbol_table eh_key_file_add_group( Eh_key_file f ,
00097 const gchar* group_name ,
00098 gboolean replace )
00099 {
00100
00101 GList* group_list = g_hash_table_lookup( f->t , group_name );
00102 Eh_symbol_table group;
00103
00104
00105 if ( !group_list || (group_list&&!replace) )
00106 {
00107 Eh_symbol_table new_tab = eh_symbol_table_new();
00108
00109
00110 group_list = g_list_prepend(group_list,new_tab);
00111
00112
00113 g_hash_table_insert( f->t ,
00114 g_strdup( group_name ) ,
00115 group_list );
00116
00117
00118 f->l = g_list_append( f->l , g_strdup( group_name ));
00119
00120 group = new_tab;
00121 }
00122 else
00123 group = g_list_first(group_list)->data;
00124
00125 eh_require( group );
00126
00127
00128 return group;
00129 }
00130
00140 void add_record_value( gpointer key , gpointer value , gpointer user_data )
00141 {
00142 Eh_key_file f = ((gpointer*)user_data)[0];
00143 gchar* group_name = ((gpointer*)user_data)[1];
00144 eh_key_file_set_value( f , group_name , key , value );
00145 }
00146
00152 Eh_key_file eh_key_file_new( )
00153 {
00154 Eh_key_file f;
00155
00156 NEW_OBJECT( Eh_key_file , f );
00157
00158 f->t = g_hash_table_new_full( &g_str_hash ,
00159 &g_str_equal ,
00160 (GDestroyNotify)&eh_free_mem ,
00161 NULL );
00162 f->l = NULL;
00163
00164 return f;
00165 }
00166
00173 Eh_key_file eh_key_file_destroy( Eh_key_file f )
00174 {
00175 if ( f )
00176 {
00177 GList* link;
00178
00179 g_hash_table_foreach( f->t , (GHFunc)&destroy_hash_table_list , NULL );
00180 g_hash_table_destroy( f->t );
00181
00182 for ( link=f->l ; link ; link=link->next )
00183 eh_free( link->data );
00184 g_list_free( f->l );
00185
00186 eh_free( f );
00187 }
00188 return NULL;
00189 }
00190
00198 gboolean eh_key_file_has_group( Eh_key_file f , const gchar* group_name )
00199 {
00200 if ( f && g_hash_table_lookup( f->t , group_name ) )
00201 return TRUE;
00202 else
00203 return FALSE;
00204 }
00205
00214 gboolean eh_key_file_has_key( Eh_key_file f , const gchar* group_name , const gchar* key )
00215 {
00216 if ( f )
00217 {
00218 GList* group = g_hash_table_lookup( f->t , group_name );
00219 if ( group && eh_symbol_table_lookup( group->data , key ) )
00220 return TRUE;
00221 else
00222 return FALSE;
00223 }
00224 else
00225 return FALSE;
00226 }
00227
00234 gchar** eh_key_file_get_groups( Eh_key_file f )
00235 {
00236 gchar** groups = NULL;
00237
00238 if ( f )
00239 {
00240 gchar* group_name_list = g_strdup( "\0");
00241
00242 g_hash_table_foreach( f->t , &dup_key , &group_name_list );
00243
00244 groups = g_strsplit( group_name_list , "\n" , 0 );
00245
00246 eh_free( group_name_list );
00247 }
00248
00249 return groups;
00250 }
00251
00259 gint eh_key_file_group_size( Eh_key_file f ,
00260 const gchar* group_name )
00261 {
00262 GList* group = g_hash_table_lookup( f->t , group_name );
00263 return g_list_length( group );
00264 }
00265
00275 gint eh_key_file_size( Eh_key_file f )
00276 {
00277 gint len = 0;
00278 if ( f )
00279 {
00280 len = g_list_length( f->l );
00281 }
00282 return len;
00283 }
00284
00295 gchar** eh_key_file_get_keys( Eh_key_file f , const gchar* group_name )
00296 {
00297 gchar** keys = NULL;
00298
00299 if ( f )
00300 {
00301 GList* group = g_hash_table_lookup( f->t , group_name );
00302
00303 if ( group )
00304 {
00305 Eh_symbol_table first_group = group->data;
00306 gchar* key_list = "";
00307
00308 eh_symbol_table_foreach( first_group , &dup_key , &key_list );
00309
00310 keys = g_strsplit( key_list , "\n" , -1 );
00311
00312 eh_free( key_list );
00313 }
00314 }
00315
00316 return keys;
00317 }
00318
00330 gchar** eh_key_file_get_all_values( Eh_key_file f , const gchar* group_name , const gchar* key )
00331 {
00332 gchar** value = NULL;
00333
00334 if ( f )
00335 {
00336 GList* group = g_hash_table_lookup( f->t , group_name );
00337 if ( group )
00338 value = eh_key_file_list_to_array( group , (gchar*)key );
00339 }
00340
00341 return value;
00342 }
00343
00356 gchar*
00357 eh_key_file_get_value( Eh_key_file f , const gchar* group_name , const gchar* key )
00358 {
00359 gchar* value = NULL;
00360
00361 if ( f )
00362 {
00363 GList* group = g_hash_table_lookup( f->t , group_name );
00364 if ( group )
00365 value = g_strdup( eh_symbol_table_lookup( group->data , (gchar*)key ) );
00366 }
00367
00368 return value;
00369 }
00370
00384 gchar*
00385 eh_key_file_get_str_value( Eh_key_file f , const gchar* group_name , const gchar* key )
00386 {
00387 return eh_key_file_get_value( f , group_name , key );
00388 }
00389
00401 gchar**
00402 eh_key_file_get_str_values( Eh_key_file f , const gchar* group_name , const gchar* key )
00403 {
00404 return eh_key_file_get_all_values(f,group_name,key);
00405 }
00406
00415 gboolean eh_key_file_get_bool_value( Eh_key_file f ,
00416 const gchar* group_name ,
00417 const gchar* key )
00418 {
00419 gchar* str = eh_key_file_get_value(f,group_name,key);
00420 gboolean ans = eh_str_to_boolean( str , NULL );
00421
00422 eh_free( str );
00423
00424 return ans;
00425 }
00426
00437 gboolean* eh_key_file_get_bool_values( Eh_key_file f ,
00438 const gchar* group_name ,
00439 const gchar* key )
00440 {
00441 guint len = eh_key_file_group_size(f,group_name);
00442 gchar** str = eh_key_file_get_all_values(f,group_name,key);
00443 gboolean* ans = eh_new( gboolean , len );
00444 guint i;
00445
00446 for ( i=0 ; i<len ; i++ )
00447 ans[i] = eh_str_to_boolean( str[i] , NULL );
00448
00449 g_strfreev( str );
00450
00451 return ans;
00452 }
00453
00462 double eh_key_file_get_dbl_value( Eh_key_file f ,
00463 const gchar* group_name ,
00464 const gchar* key )
00465 {
00466 double ans;
00467 gchar* str = eh_key_file_get_value(f,group_name,key);
00468
00469 if ( str ) ans = g_strtod( str , NULL );
00470 else ans = eh_nan();
00471
00472 eh_free( str );
00473
00474 return ans;
00475 }
00476
00486 double*
00487 eh_key_file_get_dbl_array( Eh_key_file f ,
00488 const gchar* group_name ,
00489 const gchar* key ,
00490 gint* len )
00491 {
00492 double* d_array = NULL;
00493
00494 eh_require( key );
00495 eh_require( group_name );
00496 eh_require( len );
00497
00498 if ( f )
00499 {
00500 gchar* str = eh_key_file_get_value( f , group_name , key );
00501 gchar** str_array = g_strsplit_set( str , ",;" , -1 );
00502
00503 *len = g_strv_length( str_array );
00504
00505 if ( *len > 0 )
00506 {
00507 gint i;
00508 d_array = eh_new( double , *len );
00509 for ( i=0 ; i<*len ; i++ )
00510 d_array[i] = g_strtod( str_array[i] , NULL );
00511 }
00512
00513 eh_free( str );
00514 g_strfreev( str_array );
00515 }
00516
00517 return d_array;
00518 }
00519
00530 double* eh_key_file_get_dbl_values( Eh_key_file f ,
00531 const gchar* group_name ,
00532 const gchar* key )
00533 {
00534 guint len = eh_key_file_group_size(f,group_name);
00535 gchar** str = eh_key_file_get_all_values(f,group_name,key);
00536 double* ans = eh_new( double , len );
00537 guint i;
00538
00539 for ( i=0 ; i<len ; i++ )
00540 ans[i] = g_strtod( str[i] , NULL );
00541
00542 g_strfreev( str );
00543
00544 return ans;
00545 }
00546
00547 gint
00548 eh_key_file_get_int_value( Eh_key_file f ,
00549 const gchar* group_name ,
00550 const gchar* key )
00551 {
00552 gint ans;
00553 gchar* str = eh_key_file_get_value(f,group_name,key);
00554
00555 if ( str ) ans = g_ascii_strtoll( str , NULL , 10 );
00556 else ans = G_MAXINT;
00557
00558 eh_free( str );
00559
00560 return ans;
00561 }
00562
00578 void eh_key_file_set_value( Eh_key_file f ,
00579 const gchar* group_name ,
00580 const gchar* key ,
00581 const gchar* value )
00582 {
00583 eh_require( f );
00584
00585 {
00586 Eh_symbol_table group;
00587
00588
00589 if ( !eh_key_file_has_group( f , group_name )
00590 || eh_key_file_has_key( f , group_name , key ) )
00591 group = eh_key_file_add_group( f , group_name , FALSE );
00592 else
00593 group = g_list_first(g_hash_table_lookup( f->t , group_name ))->data;
00594
00595
00596 eh_require( group );
00597
00598
00599 eh_symbol_table_insert( group , g_strdup( key ) , g_strdup( value ) );
00600 }
00601 }
00602
00618 void eh_key_file_reset_value( Eh_key_file f ,
00619 const gchar* group_name ,
00620 const gchar* key ,
00621 const gchar* value )
00622 {
00623 Eh_symbol_table group;
00624
00625 eh_require( f );
00626
00627 group = eh_key_file_add_group( f , group_name , TRUE );
00628
00629 eh_symbol_table_insert( group , g_strdup( key ) , g_strdup( value ) );
00630 }
00631
00632
00644 Eh_symbol_table eh_key_file_get_symbol_table( Eh_key_file f ,
00645 const gchar* group_name )
00646 {
00647 GList* group = g_hash_table_lookup( f->t , group_name );
00648 return eh_symbol_table_dup( group->data );
00649 }
00650
00663 Eh_symbol_table*
00664 eh_key_file_get_symbol_tables( Eh_key_file f , const gchar* group_name )
00665 {
00666 Eh_symbol_table* value = NULL;
00667
00668 if ( f )
00669 {
00670 GList* group = g_hash_table_lookup( f->t , group_name );
00671 if ( group )
00672 {
00673 GList* l;
00674 guint i;
00675 guint len = eh_key_file_group_size( f , group_name );
00676
00677 value = g_new( Eh_symbol_table , len+1 );
00678 for ( i=0,l=group ; l ; i++, l=l->next )
00679 value[i] = eh_symbol_table_dup( l->data );
00680 value[len] = NULL;
00681 }
00682 }
00683 return value;
00684 }
00685
00692 void print_keys( gpointer key , gpointer value , gpointer user_data )
00693 {
00694 eh_message( "KEY = %s" , (gchar*)key );
00695 }
00696
00707 Eh_key_file
00708 eh_key_file_scan( const char* file , GError** error )
00709 {
00710 Eh_key_file f = NULL;
00711
00712 eh_return_val_if_fail( error==NULL || *error==NULL , NULL );
00713
00714 f = eh_key_file_new();
00715
00716 if ( f )
00717 {
00718 GError* tmp_err = NULL;
00719 GScanner* s;
00720
00721 s = eh_open_scanner( file , &tmp_err );
00722
00723 if ( s )
00724 {
00725 gboolean done = FALSE;
00726 gchar* group_name;
00727 Eh_symbol_table symbol_table;
00728 gpointer user_data[2];
00729
00730 while( !done && !g_scanner_eof(s) )
00731 {
00732 symbol_table = eh_symbol_table_new();
00733 group_name = eh_scan_next_record( s , symbol_table );
00734
00735 if ( group_name )
00736 {
00737 user_data[0] = f;
00738 user_data[1] = group_name;
00739
00740 eh_symbol_table_foreach( symbol_table , &add_record_value , user_data );
00741 }
00742 else
00743 done = TRUE;
00744
00745 eh_symbol_table_destroy( symbol_table );
00746 eh_free( group_name );
00747 }
00748
00749 eh_close_scanner( s );
00750 }
00751 else
00752 {
00753 f = eh_key_file_destroy( f );
00754 g_propagate_error( error , tmp_err );
00755 }
00756 }
00757
00758 return f;
00759 }
00760
00761 gint
00762 eh_key_file_scan_from_template( const gchar* file ,
00763 const gchar* group_name ,
00764 Eh_key_file_entry t[] ,
00765 GError** error )
00766 {
00767 gint n_entries = 0;
00768
00769 eh_return_val_if_fail( error==NULL || *error==NULL , 0 );
00770
00771 if ( file )
00772 {
00773 GError* tmp_error = NULL;
00774 Eh_key_file f = NULL;
00775 gchar** missing_entries = NULL;
00776 gint* len;
00777 gint i;
00778
00779 for ( n_entries=0 ; t[n_entries].label ; n_entries++ );
00780
00781 for ( i=0 ; i<n_entries ; i++ )
00782 if ( t[i].arg == EH_ARG_DARRAY )
00783 {
00784 eh_require( t[i].arg_data_len );
00785 eh_return_val_if_fail( t[i].arg_data_len , 0 );
00786
00787 *(t[i].arg_data_len) = 0;
00788 }
00789
00790 len = eh_new( gint , n_entries );
00791
00792 f = eh_key_file_scan( file , &tmp_error );
00793
00794 for ( i=0 ; i<n_entries && !tmp_error ; i++ )
00795 {
00796 if ( eh_key_file_has_key( f , group_name , t[i].label ) )
00797 {
00798 switch ( t[i].arg )
00799 {
00800 case EH_ARG_DBL:
00801 *(double* )(t[i].arg_data) = eh_key_file_get_dbl_value( f , group_name , t[i].label );
00802 break;
00803 case EH_ARG_INT:
00804 *(gint* )(t[i].arg_data) = eh_key_file_get_dbl_value( f , group_name , t[i].label );
00805 break;
00806 case EH_ARG_DARRAY:
00807 *(double**)(t[i].arg_data) = eh_key_file_get_dbl_array( f , group_name , t[i].label , &(len[i]) );
00808
00809 if ( *(t[i].arg_data_len)==0 || *(t[i].arg_data_len)==len[i] )
00810 *(t[i].arg_data_len) = len[i];
00811 else
00812 g_set_error( &tmp_error ,
00813 EH_KEY_FILE_ERROR ,
00814 EH_KEY_FILE_ERROR_ARRAY_LEN_MISMATCH ,
00815 "%s: Array length mismatch (%d!=%d): %s\n" ,
00816 file , len[i] , *(t[i].arg_data_len) , t[i].label );
00817
00818 break;
00819 case EH_ARG_FILENAME:
00820 *(gchar**)(t[i].arg_data) = eh_key_file_get_value( f , group_name , t[i].label );
00821 break;
00822 }
00823 }
00824 else
00825 eh_strv_append( &missing_entries , g_strconcat(file , ": Missing required entry: " , t[i].label , NULL ) );
00826
00827 }
00828
00829 if ( !tmp_error && missing_entries )
00830 {
00831 gchar* missing_list = g_strjoinv( "\n" , missing_entries );
00832
00833 g_set_error( &tmp_error ,
00834 EH_KEY_FILE_ERROR ,
00835 EH_KEY_FILE_ERROR_MISSING_ENTRY ,
00836 "%s\n" , missing_list );
00837
00838 eh_free( missing_list );
00839 }
00840
00841 if ( tmp_error )
00842 g_propagate_error( error , tmp_error );
00843
00844 g_strfreev( missing_entries );
00845 eh_free( len );
00846 eh_key_file_destroy( f );
00847 }
00848
00849 return n_entries;
00850 }
00851
00852 gssize
00853 eh_key_file_fprint_template( FILE* fp ,
00854 const gchar* group_name ,
00855 Eh_key_file_entry entry[] )
00856 {
00857 gint n = 0;
00858
00859 if ( fp )
00860 {
00861 gint n_entries;
00862 gint max_len = 0;
00863 gchar* pad;
00864 gint i;
00865
00866 for ( n_entries=0 ; entry[n_entries].label ; n_entries++ );
00867
00868 for ( i=0 ; i<n_entries ; i++ )
00869 if ( strlen( entry[i].label ) > max_len )
00870 max_len = strlen( entry[i].label );
00871
00872 pad = g_strnfill( max_len , ' ' );
00873
00874 fprintf( fp , "[ %s ]" , group_name );
00875
00876 for ( i=0 ; i<n_entries ; i++ )
00877 {
00878 n += fprintf( fp , "%s :%s" , entry[i].label , pad + strlen( entry[i].label ) );
00879
00880 switch ( entry[i].arg )
00881 {
00882 case EH_ARG_DBL:
00883 n += fprintf( fp , "%s\n" , "<double-scalar>" );
00884 break;
00885 case EH_ARG_INT:
00886 n += fprintf( fp , "%s\n" , "<int-scalar>" );
00887 break;
00888 case EH_ARG_DARRAY:
00889 n += fprintf( fp , "%s\n" , "<double-array>" );
00890 break;
00891 case EH_ARG_FILENAME:
00892 n += fprintf( fp , "%s\n" , "<filename>" );
00893 break;
00894 }
00895 }
00896
00897 eh_free( pad );
00898 }
00899
00900 return n;
00901 }
00902
00919 Eh_symbol_table
00920 eh_key_file_scan_for( const gchar* file ,
00921 const gchar* name ,
00922 Eh_symbol_table tab ,
00923 GError** error )
00924 {
00925 Eh_symbol_table new_tab = NULL;
00926
00927 eh_return_val_if_fail( error==NULL || *error==NULL , NULL );
00928
00929
00930
00931
00932
00933
00934 {
00935 GError* tmp_err = NULL;
00936 Eh_key_file key_file = eh_key_file_scan( file , &tmp_err );
00937
00938 if ( key_file )
00939 {
00940 if ( eh_key_file_has_group( key_file , name ) )
00941 new_tab = eh_key_file_get_symbol_table( key_file , name );
00942 else
00943 new_tab = NULL;
00944 }
00945 else
00946 g_propagate_error( error , tmp_err );
00947
00948 eh_key_file_destroy( key_file );
00949 }
00950
00951 if ( tab && new_tab )
00952 {
00953 eh_symbol_table_copy ( tab , new_tab );
00954 eh_symbol_table_destroy( new_tab );
00955
00956 new_tab = tab;
00957 }
00958
00959 return new_tab;
00960 }
00961
00972 Eh_symbol_table eh_key_file_pop_group( Eh_key_file f )
00973 {
00974 Eh_symbol_table new_table = NULL;
00975
00976 if ( f && f->l )
00977 {
00978 gchar* group_name = g_list_first(f->l)->data;
00979 GList* group_list = g_hash_table_lookup( f->t , group_name );
00980
00981 eh_require( group_list );
00982
00983
00984 new_table = g_list_first( group_list )->data;
00985
00986
00987 group_list = g_list_delete_link( group_list , group_list );
00988
00989 if ( group_list )
00990
00991 g_hash_table_replace( f->t , g_strdup(group_name) , group_list );
00992 else
00993
00994 g_hash_table_remove( f->t , group_name );
00995
00996
00997 eh_free( group_name );
00998 f->l = g_list_delete_link( f->l , f->l );
00999 }
01000
01001 return new_table;
01002 }
01003