Nilorea Library
C utilities for networking, threading, graphics
n_config_file.c
Go to the documentation of this file.
1
7#include <stdio.h>
8#include <errno.h>
9
10#include "nilorea/n_common.h"
12#include "nilorea/n_pcre.h"
13
14
19void free_no_null( void *ptr )
20{
21 char *strptr = ptr ;
22 if( strptr )
23 {
24 free( strptr );
25 }
26 return ;
27}
28
34{
36 if( !section )
37 return ;
38 Free( section -> section_name );
39 destroy_ht( &section -> entries );
40 Free( section );
41} /* destroy_config_file_section(...) */
42
43
44
51CONFIG_FILE *load_config_file( char *filename, int *errors )
52{
53 CONFIG_FILE *cfg_file = NULL ;
54 CONFIG_FILE_SECTION *section = NULL ;
55 char buffer[ MAX_CONFIG_LINE_LEN ] = "" ;
56 char **split_result = NULL ;
57 N_PCRE *npcre = npcre_new( "(.*?=)(.*)", 99, 0 );
58 int error = 0 ;
59 FILE *in = NULL ;
60
61 __n_assert( filename, return NULL );
62 in = fopen( filename, "r" );
63 error = errno ;
64 if( !in )
65 {
66 n_log( LOG_ERR, "Unable to open %s: %s", _str( filename ), strerror( error ) );
67 (*errors)++;
68 npcre_delete( &npcre );
69 return NULL ;
70 }
71 Malloc( cfg_file, CONFIG_FILE, 1 );
72 if( !cfg_file )
73 {
74 fclose( in );
75 npcre_delete( &npcre );
76 return NULL ;
77 }
78 cfg_file -> sections = new_generic_list( 0 );
79 if( !cfg_file -> sections )
80 {
81 Free( cfg_file );
82 fclose( in );
83 npcre_delete( &npcre );
84 return NULL ;
85 }
86 cfg_file -> filename = strdup( filename );
87 if( !cfg_file -> filename )
88 {
89 n_log( LOG_ERR, "couldn't strdup( %s )", _str( filename ) );
90 (*errors)++;
91 Free( cfg_file );
92 fclose( in );
93 npcre_delete( &npcre );
94 return NULL ;
95 }
96 /* adding default section */
97 CONFIG_FILE_SECTION *default_section = NULL ;
98 Malloc( default_section, CONFIG_FILE_SECTION, 1 );
99 if( !default_section )
100 {
101 n_log( LOG_ERR, "couldn't allocate default_section" );
102 (*errors)++;
103 Free( cfg_file );
104 fclose( in );
105 npcre_delete( &npcre );
106 return NULL ;
107 }
108
109 default_section -> section_name = strdup( "__DEFAULT__" );
110 if( !default_section -> section_name )
111 {
112 n_log( LOG_ERR, "couldn't allocate default_section name" );
113 (*errors)++;
114 Free( cfg_file );
115 Free( default_section );
116 fclose( in );
117 npcre_delete( &npcre );
118 return NULL ;
119 }
120
121 default_section -> entries = new_ht( CONFIG_SECTION_HASH_TABLE_LEN );
122 if( !default_section -> entries )
123 {
124 n_log( LOG_ERR, "error creating hash table of size %d for default_section", CONFIG_SECTION_HASH_TABLE_LEN );
125 (*errors)++;
126 Free( default_section -> section_name );
127 Free( default_section );
128 Free( cfg_file );
129 fclose( in );
130 npcre_delete( &npcre );
131 return NULL ;
132 }
133 list_push( cfg_file -> sections, default_section, &destroy_config_file_section );
134
135 int line_number = 0 ;
136 while( fgets( buffer, MAX_CONFIG_LINE_LEN, in ) )
137 {
138 NSTRBYTE start = 0, end = 0 ;
139
140 char *bufptr = (char *)&buffer ;
141 line_number ++ ;
142
143 bufptr = trim_nocopy( buffer );
144 if( strlen( bufptr ) == 0 )
145 {
146 continue ;
147 }
148
149 switch( bufptr[ 0 ] )
150 {
151 /* comment */
152 case '#' :
153 case ';' :
154 continue ;
155 /* new section */
156 case '[' :
157 end = 0 ;
158 /* go to begin of section name */
159 if( skipu( bufptr, ']', &end, 1 ) != TRUE )
160 {
161 n_log( LOG_ERR, "coulnd't find end of section at line %d of %s (string:%s)", line_number, filename, buffer );
162 (*errors)++;
163 continue ;
164 }
165 /* keep only the name */
166 bufptr ++ ;
167 bufptr[ end - 1 ] = '\0' ;
168 bufptr = trim_nocopy( bufptr );
169 if( strlen( bufptr ) == 0 )
170 {
171 n_log( LOG_ERR, "section without name at line %d", line_number );
172 (*errors)++;
173 continue ;
174 }
175
176 Malloc( section, CONFIG_FILE_SECTION, 1 );
177 __n_assert( section, break );
178
179 section -> section_name = strdup( bufptr );
180 if( !section -> section_name )
181 {
182 n_log( LOG_ERR, "couldn't duplicate %s", bufptr );
183 (*errors)++;
184 continue ;
185 }
186
187 section -> entries = new_ht( CONFIG_SECTION_HASH_TABLE_LEN );
188 if( !section -> entries )
189 {
190 n_log( LOG_ERR, "error creating [%s] hash table of size %d", bufptr, CONFIG_SECTION_HASH_TABLE_LEN );
191 (*errors)++;
192 continue ;
193 }
194 list_push( cfg_file -> sections, section, &destroy_config_file_section );
195 continue ;
196
197 /* if it's not a comment, not a section, not empty, then it's an entry ! */
198 default:
199 if( !section )
200 {
201 section = default_section ;
202 n_log( LOG_DEBUG, "No section, setting __DEFAULT__ starting line %d of %s (string:%s)", line_number, filename, bufptr );
203 }
204
205 if( npcre_match( bufptr, npcre ) == TRUE )
206 {
207 Malloc( split_result, char *, 3 );
208
209 split_result[ 2 ] = NULL ;
210 split_result[ 0 ] = str_replace( npcre -> match_list[ 1 ], "=", " " );
211 split_result[ 1 ] = strdup( npcre -> match_list[ 2 ] );
212 }
213 else
214 {
215 split_result = NULL ;
216 }
217
218 if( !split_result )
219 {
220 n_log( LOG_ERR, "couldn't find entry separator '=' at line %d of %s (string:%s)", line_number, filename, bufptr );
221 (*errors)++;
222 continue ;
223 }
224 if( split_count( split_result ) < 2 )
225 {
226 n_log( LOG_ERR, "Invalid split count at line %d of %s (string:%s, count:%d)", line_number, filename, bufptr, split_count( split_result ) );
227 (*errors)++;
228 free_split_result( &split_result );
229 continue ;
230 }
231 if( strlen( trim_nocopy( split_result[ 0 ] ) ) == 0 )
232 {
233 free_split_result( &split_result );
234 n_log( LOG_ERR, "couldn't find entry name at line %d of %s (string:%s)", line_number, filename, buffer[ start ] );
235 (*errors)++;
236 continue ;
237 }
238
239 /* value pointer */
240 char *valptr = NULL ;
241 /* flags */
242 int closing_delimiter_found = 0 ;
243 int opening_delimiter_found = 0 ;
244 /* initialize with empty delimiter */
245 char delimiter = '\0' ;
246
247 /* If the trimmed value have a zero length it means we only had spaces or tabs
248 In that particular case we set the val to NULL */
249 if( strlen( trim_nocopy( split_result[ 1 ] ) ) == 0 )
250 {
251 Free( split_result[ 1 ] );
252 valptr = NULL ;
253 delimiter = '\0' ;
254 }
255 else /* we have a value, or something between delimiters */
256 {
257 valptr = trim_nocopy( split_result[ 1 ] );
258 int it = strlen( valptr );
259
260 /* get value right boundary */
261 while( it >= 0 )
262 {
263 /* if comments tags replace them with end of string */
264 if( split_result[ 1 ][ it ] == ';' || split_result[ 1 ][ it ] == '#' )
265 {
266 split_result[ 1 ][ it ] = '\0' ;
267 }
268 else
269 {
270 /* we found a delimiter on the right */
271 if( split_result[ 1 ][ it ] == '"' || split_result[ 1 ][ it ] == '\'' )
272 {
273 delimiter = split_result[ 1 ][ it ] ;
274 split_result[ 1 ][ it ] = '\0' ;
275 closing_delimiter_found = 1 ;
276 break ;
277 }
278 }
279 it-- ;
280 }
281
282 if( strlen( trim_nocopy( split_result[ 1 ] ) ) == 0 )
283 {
284 Free( split_result[ 1 ] );
285 valptr = NULL ;
286 delimiter = '\0' ;
287 }
288
289 /* get value left boundary */
290 it = 0 ;
291 while( split_result[ 1 ][ it ] != '\0' )
292 {
293 if( split_result[ 1 ][ it ] == ';' || split_result[ 1 ][ it ] == '#' )
294 {
295 split_result[ 1 ][ it ] = '\0' ;
296 }
297 else
298 {
299 if( delimiter != '\0' && split_result[ 1 ][ it ] == delimiter )
300 {
301 opening_delimiter_found = 1 ;
302 it ++ ;
303 valptr = split_result[ 1 ]+ it ;
304 break ;
305 }
306 it ++ ;
307 }
308 }
309 if( strlen( trim_nocopy( split_result[ 1 ] ) ) == 0 )
310 {
311 Free( split_result[ 1 ] );
312 valptr = NULL ;
313 delimiter = '\0' ;
314 }
315 }
316 if( delimiter != '\0' && ( ( opening_delimiter_found && !closing_delimiter_found ) || ( !opening_delimiter_found && closing_delimiter_found ) ) )
317 {
318 free_split_result( &split_result );
319 n_log( LOG_ERR, "Only one delimiter found at line %d of %s (string:%s)", line_number, filename, buffer );
320 (*errors)++;
321 continue ;
322 }
323
324 char *result = NULL ;
325 N_STR *entry_key = NULL ;
326 int nb_entry_in_sections = 0 ;
327 while( TRUE )
328 {
329 nstrprintf( entry_key, "%s%d", trim_nocopy( split_result[ 0 ] ), nb_entry_in_sections );
330 if( ht_get_ptr( section -> entries, _nstr( entry_key ), (void **)&result ) == FALSE )
331 {
332 break ;
333 }
334 nb_entry_in_sections ++ ;
335 free_nstr( &entry_key );
336 }
337 char *strptr = NULL ;
338 if( valptr )
339 {
340 strptr = strdup( valptr );
341 }
342 ht_put_ptr( section -> entries, _nstr( entry_key ), strptr, &free_no_null );
343 free_nstr( &entry_key );
344 free_split_result( &split_result );
345 continue ;
346 }
347 }
348 npcre_delete( &npcre );
349 if( !feof( in ) )
350 {
351 n_log( LOG_ERR, "couldn't read EOF for %s", filename );
352 (*errors)++;
353 }
354 fclose( in );
355
356 return cfg_file ;
357
358} /*load_config_file */
359
360
361
368int write_config_file( CONFIG_FILE *cfg_file, char *filename )
369{
370 __n_assert( cfg_file, return FALSE );
371 __n_assert( filename, return FALSE );
372
373 FILE *out = NULL ;
374 out = fopen( filename, "w" );
375 int error = errno ;
376 __n_assert( out, n_log( LOG_ERR, "Could not open %s, %s", filename, strerror( error ) ); return FALSE );
377
378 char *last_section = NULL ;
379 char *section = NULL, *key = NULL, *val = NULL ;
380
381 config_foreach( cfg_file, section, key, val )
382 {
383 /* write section name */
384 if( !last_section || strcmp( last_section, section ) != 0 )
385 {
386 fprintf( out, "[%s]\n", section );
387 FreeNoLog( last_section );
388 last_section = strdup( section );
389 }
390 fprintf( out, "%s=%s\n", key, val );
391 }
393 fclose( out );
394 FreeNoLog( last_section );
395
396 return TRUE ;
397} /* write_config_file */
398
399
400
401
408int get_nb_config_file_sections( CONFIG_FILE *cfg_file, char *section_name )
409{
410 __n_assert( cfg_file, return -1 );
411 __n_assert( cfg_file -> sections, return -2 );
412
413 int nb_sections = 0 ;
414 list_foreach( listnode, cfg_file -> sections )
415 {
416 CONFIG_FILE_SECTION *section = (CONFIG_FILE_SECTION *)listnode -> ptr ;
417 if( section_name )
418 {
419 if( !strcmp( section -> section_name, section_name ) )
420 {
421 nb_sections ++ ;
422 }
423 }
424 else
425 {
426 nb_sections ++ ;
427 }
428 }
429 return nb_sections ;
430} /* get_nb_config_file_sections(...) */
431
432
433
442int get_nb_config_file_sections_entries( CONFIG_FILE *cfg_file, char *section_name, int section_position, char *entry )
443{
444 __n_assert( cfg_file, return -1 );
445 __n_assert( cfg_file -> sections, return -2 );
446 __n_assert( section_name, return -3 );
447 __n_assert( entry, return -4 );
448
449 int nb_sections = 0 ;
450 int nb_entry_in_sections = 0 ;
451 list_foreach( listnode, cfg_file -> sections )
452 {
453 CONFIG_FILE_SECTION *section = (CONFIG_FILE_SECTION *)listnode -> ptr ;
454 if( !strcmp( section -> section_name, section_name ) )
455 {
456 if( nb_sections == section_position )
457 {
458 char *result = NULL ;
459 N_STR *entry_key = NULL ;
460 while( TRUE )
461 {
462 nstrprintf( entry_key, "%s%d", entry, nb_entry_in_sections );
463 if( ht_get_ptr( section -> entries, _nstr( entry_key ), (void **)&result ) == FALSE )
464 {
465 free_nstr( &entry_key );
466 break ;
467 }
468 nb_entry_in_sections ++ ;
469 free_nstr( &entry_key );
470 }
471 break ;
472 }
473 nb_sections ++ ;
474 }
475 }
476 return nb_entry_in_sections ;
477} /* get_nb_config_file_sections_entries(...) */
478
479
480
490char *get_config_section_value( CONFIG_FILE *cfg_file, char *section_name, int section_position, char *entry, int entry_position )
491{
492 __n_assert( cfg_file, return NULL );
493 __n_assert( cfg_file -> sections, return NULL );
494 __n_assert( section_name, return NULL );
495 __n_assert( entry, return NULL );
496
497 if( section_position >= cfg_file -> sections -> nb_items )
498 {
499 n_log( LOG_DEBUG, "section_position (%d) is higher than the number of item in list (%d)", section_position, cfg_file -> sections -> nb_items );
500 return NULL ;
501 }
502
503 int section_position_it = 0 ;
504 HASH_TABLE *entries = NULL ;
505 list_foreach( listnode, cfg_file -> sections )
506 {
507 CONFIG_FILE_SECTION *section = (CONFIG_FILE_SECTION *)listnode -> ptr ;
508 if( !strcmp( section -> section_name, section_name ) )
509 {
510 if( section_position_it == section_position )
511 {
512 entries = section -> entries ;
513 break ;
514 }
515 section_position_it ++ ;
516 }
517 }
518
519 char *result = NULL ;
520 N_STR *entry_key = NULL ;
521 nstrprintf( entry_key, "%s%d", entry, entry_position );
522 if( ht_get_ptr( entries, _nstr( entry_key ), (void **)&result ) == FALSE )
523 {
524 /* n_log( LOG_DEBUG , "ht_get_ptr( %p , trim_nocopy( %s ) , (void **)&result ) returned FALSE !" , entries , _nstr( entry_key ) ); */
525 free_nstr( &entry_key );
526 return NULL ;
527 }
528 free_nstr( &entry_key );
529
530 return result ;
531} /* get_config_section_value */
532
533
534
541{
542 __n_assert( cfg_file&&(*cfg_file), return FALSE );
543
544 Free( (*cfg_file) -> filename );
545
546 if( (*cfg_file) -> sections )
547 {
548 list_destroy( &(*cfg_file) -> sections );
549 }
550
551 Free( (*cfg_file) );
552
553 return TRUE ;
554} /* destroy_config_file */
#define FreeNoLog(__ptr)
Free Handler without log.
Definition: n_common.h:268
#define Malloc(__ptr, __struct, __size)
Malloc Handler to get errors and set to 0.
Definition: n_common.h:183
#define __n_assert(__ptr, __ret)
macro to assert things
Definition: n_common.h:276
#define _str(__PTR)
define true
Definition: n_common.h:172
#define Free(__ptr)
Free Handler to get errors.
Definition: n_common.h:256
#define _nstr(__PTR)
N_STR or "NULL" string for logging purposes.
Definition: n_common.h:178
CONFIG_FILE * load_config_file(char *filename, int *errors)
load a config file
Definition: n_config_file.c:51
int write_config_file(CONFIG_FILE *cfg_file, char *filename)
write a config file
char * get_config_section_value(CONFIG_FILE *cfg_file, char *section_name, int section_position, char *entry, int entry_position)
Function to parse sections and get entries values.
#define config_endfor
Foreach elements of CONFIG_FILE macro END.
Definition: n_config_file.h:80
#define CONFIG_SECTION_HASH_TABLE_LEN
size of the hash table of config sections entries
Definition: n_config_file.h:29
int destroy_config_file(CONFIG_FILE **cfg_file)
Destroy a loaded config file.
#define MAX_CONFIG_LINE_LEN
maximum length of a single config line
Definition: n_config_file.h:27
#define config_foreach(__config, __section_name, __key, __val)
Foreach elements of CONFIG_FILE macro, i.e config_foreach( config , section , key ,...
Definition: n_config_file.h:60
int get_nb_config_file_sections(CONFIG_FILE *cfg_file, char *section_name)
Get the number of config file with section_name.
int get_nb_config_file_sections_entries(CONFIG_FILE *cfg_file, char *section_name, int section_position, char *entry)
Get the number of config file with section_name.
Structure of a config file.
Definition: n_config_file.h:41
Structure of a config section.
Definition: n_config_file.h:33
int ht_get_ptr(HASH_TABLE *table, const char *key, void **val)
get pointer at 'key' from 'table'
Definition: n_hash.c:2282
int destroy_ht(HASH_TABLE **table)
empty a table and destroy it
Definition: n_hash.c:2448
HASH_TABLE * new_ht(size_t size)
Create a hash table with the given size.
Definition: n_hash.c:2167
int ht_put_ptr(HASH_TABLE *table, const char *key, void *ptr, void(*destructor)(void *ptr))
put a pointer to the string value with given key in the targeted hash table
Definition: n_hash.c:2347
structure of a hash table
Definition: n_hash.h:109
int list_push(LIST *list, void *ptr, void(*destructor)(void *ptr))
Add a pointer to the end of the list.
Definition: n_list.c:244
#define list_foreach(__ITEM_, __LIST_)
ForEach macro helper.
Definition: n_list.h:70
int list_destroy(LIST **list)
Empty and Free a list container.
Definition: n_list.c:603
LIST * new_generic_list(int max_items)
Initialiaze a generic list container to max_items pointers.
Definition: n_list.c:20
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition: n_log.h:74
#define LOG_DEBUG
debug-level messages
Definition: n_log.h:66
#define LOG_ERR
error conditions
Definition: n_log.h:58
char * trim_nocopy(char *s)
trim and zero end the string, WARNING: keep and original pointer to delete the string correctly
Definition: n_str.c:124
size_t NSTRBYTE
N_STR base unit.
Definition: n_str.h:169
#define free_nstr(__ptr)
free a N_STR structure and set the pointer to NULL
Definition: n_str.h:222
int split_count(char **split_result)
Count split elements.
Definition: n_str.c:1111
#define nstrprintf(__nstr_var,...)
Macro to quickly allocate and sprintf to N_STR *.
Definition: n_str.h:97
char * str_replace(const char *string, const char *substr, const char *replacement)
Replace "substr" by "replacement" inside string taken from http://coding.debuntu.org/c-implementing-s...
Definition: n_str.c:1598
int free_split_result(char ***tab)
Free a split result allocated array.
Definition: n_str.c:1131
int skipu(char *string, char toskip, NSTRBYTE *iterator, int inc)
skip until 'toskip' occurence is found from 'iterator' to the next 'toskip' value.
Definition: n_str.c:889
A box including a string and his lenght.
Definition: n_str.h:173
N_PCRE * npcre_new(char *str, int max_cap, int flags)
From pcre doc, the flag bits are: PCRE_ANCHORED Force pattern anchoring PCRE_AUTO_CALLOUT Compile aut...
Definition: n_pcre.c:59
int npcre_match(char *str, N_PCRE *pcre)
Return TRUE if str matches regexp, and make captures up to max_cap.
Definition: n_pcre.c:165
int npcre_delete(N_PCRE **pcre)
Free a N_PCRE pointer.
Definition: n_pcre.c:107
N_PCRE structure.
Definition: n_pcre.h:29
Common headers and low-level hugly functions & define.
void free_no_null(void *ptr)
local free for config entries
Definition: n_config_file.c:19
void destroy_config_file_section(void *ptr)
Destroy a config file section.
Definition: n_config_file.c:33
Config file reading and writing.
PCRE helpers for regex matching.