diff options
Diffstat (limited to 'lib/ini.c')
-rw-r--r-- | lib/ini.c | 129 |
1 files changed, 92 insertions, 37 deletions
@@ -1,7 +1,7 @@ /********************************************************************\ * BitlBee -- An IRC to other IM-networks gateway * * * - * Copyright 2002-2005 Wilmer van der Gaast and others * + * Copyright 2002-2008 Wilmer van der Gaast and others * \********************************************************************/ /* INI file reading code */ @@ -27,64 +27,119 @@ ini_t *ini_open( char *file ) { - ini_t *ini = g_new0( ini_t, 1 ); + int fd; + ini_t *ini = NULL; + struct stat fi; - if( ( ini->fp = fopen( file, "r" ) ) == NULL ) + if( ( fd = open( file, O_RDONLY ) ) != -1 && + fstat( fd, &fi ) == 0 && + fi.st_size <= 16384 && + ( ini = g_malloc( sizeof( ini_t ) + fi.st_size + 1 ) ) && + read( fd, ini->file, fi.st_size ) == fi.st_size ) { - g_free( ini ); - return( NULL ); + memset( ini, 0, sizeof( ini_t ) ); + ini->size = fi.st_size; + ini->file[ini->size] = 0; + ini->cur = ini->file; + ini->c_section = ""; + + close( fd ); + + return ini; } + + if( fd >= 0 ) + close( fd ); - return( ini ); + ini_close( ini ); + + return NULL; +} + +/* Strips leading and trailing whitespace and returns a pointer to the first + non-ws character of the given string. */ +static char *ini_strip_whitespace( char *in ) +{ + char *e; + + while( isspace( *in ) ) + in++; + + e = in + strlen( in ) - 1; + while( e > in && isspace( *e ) ) + e--; + e[1] = 0; + + return in; } int ini_read( ini_t *file ) { - char key[MAX_STRING], s[MAX_STRING], *t; - int i; + char *s; - while( !feof( file->fp ) ) + while( file->cur && file->cur < file->file + file->size ) { - *s = 0; - fscanf( file->fp, "%127[^\n#]s", s ); - fscanf( file->fp, "%*[^\n]s" ); - fgetc( file->fp ); /* Skip newline */ - file->line ++; - if( strchr( s, '=' ) ) + char *e, *next; + + file->line++; + + /* Find the end of line */ + if( ( e = strchr( file->cur, '\n' ) ) != NULL ) + { + *e = 0; + next = e + 1; + } + else { - sscanf( s, "%[^ =]s", key ); - if( ( t = strchr( key, '.' ) ) ) + /* No more lines. */ + e = file->cur + strlen( file->cur ); + next = NULL; + } + + /* Comment? */ + if( ( s = strchr( file->cur, '#' ) ) != NULL ) + *s = 0; + + file->cur = ini_strip_whitespace( file->cur ); + + if( *file->cur == '[' ) + { + file->cur++; + if( ( s = strchr( file->cur, ']' ) ) != NULL ) { - *t = 0; - strcpy( file->section, key ); - t ++; + *s = 0; + file->c_section = file->cur; + } + } + else if( ( s = strchr( file->cur, '=' ) ) != NULL ) + { + *s = 0; + file->key = ini_strip_whitespace( file->cur ); + file->value = ini_strip_whitespace( s + 1 ); + + if( ( s = strchr( file->key, '.' ) ) != NULL ) + { + *s = 0; + file->section = file->key; + file->key = s + 1; } else { - strcpy( file->section, file->c_section ); - t = key; + file->section = file->c_section; } - sscanf( t, "%s", file->key ); - t = strchr( s, '=' ) + 1; - for( i = 0; t[i] == ' '; i ++ ); - strcpy( file->value, &t[i] ); - for( i = strlen( file->value ) - 1; file->value[i] == 32; i -- ) - file->value[i] = 0; - return( 1 ); - } - else if( ( t = strchr( s, '[' ) ) ) - { - strcpy( file->c_section, t + 1 ); - t = strchr( file->c_section, ']' ); - *t = 0; + file->cur = next; + return 1; } + /* else: noise/comment/etc, let's just ignore it. */ + + file->cur = next; } - return( 0 ); + + return 0; } void ini_close( ini_t *file ) { - fclose( file->fp ); g_free( file ); } |