Library: ini.h
#define INI_IMPLEMENTATION
#include "ini.h"
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE* fp = fopen( "test.ini", "r" );
fseek( fp, 0, SEEK_END );
int size = ftell( fp );
fseek( fp, 0, SEEK_SET );
char* data = (char*) malloc( size + 1 );
fread( data, 1, size, fp );
data[ size ] = '\0';
fclose( fp );
ini_t* ini = ini_load( data );
free( data );
int second_index = ini_find_property( ini, INI_GLOBAL_SECTION, "SecondSetting" );
char const* second = ini_property_value( ini, INI_GLOBAL_SECTION, second_index );
printf( "%s=%s\n", "SecondSetting", second );
int section = ini_find_section( ini, "MySection" );
int third_index = ini_find_property( ini, section, "ThirdSetting" );
char const* third = ini_property_value( ini, section, third_index );
printf( "%s=%s\n", "ThirdSetting", third );
ini_destroy( ini );
return 0;
}
#define INI_IMPLEMENTATION
#include "ini.h"
#include <stdio.h>
#include <stdlib.h>
int main()
{
ini_t* ini = ini_create();
ini_property_add( ini, INI_GLOBAL_SECTION, "FirstSetting", "Test" );
ini_property_add( ini, INI_GLOBAL_SECTION, "SecondSetting", "2" );
int section = ini_section_add( ini, "MySection" );
ini_property_add( ini, section, "ThirdSetting", "Three" );
int size = ini_save( ini, NULL, 0 ); // Find the size needed
char* data = (char*) malloc( size );
size = ini_save( ini, data, size ); // Actually save the file
ini_destroy( ini );
FILE* fp = fopen( "test.ini", "w" );
fwrite( data, 1, size, fp );
fclose( fp );
free( data );
return 0;
}
ini.h is a small library for reading classic .ini files. It is a single-header library, and does not need any .lib files
or other binaries, or any build scripts. To use it, you just include ini.h to get the API declarations. To get the
definitions, you must include ini.h from one single C or C++ file, and #define the symbol INI_IMPLEMENTATION
before
you do.
There are a few different things in ini.h which are configurable by #defines. The customizations only affect the implementation, so will only need to be defined in the file where you have the #define INI_IMPLEMENTATION.
Note that if all customizations are utilized, ini.h will include no external files whatsoever, which might be useful if you need full control over what code is being built.
To store the internal data structures, ini.h needs to do dynamic allocation by calling malloc
. Programs might want to
keep track of allocations done, or use custom defined pools to allocate memory from. ini.h allows for specifying custom
memory allocation functions for malloc
and free
.
This is done with the following code:
#define INI_IMPLEMENTATION
#define INI_MALLOC( ctx, size ) ( my_custom_malloc( ctx, size ) )
#define INI_FREE( ctx, ptr ) ( my_custom_free( ctx, ptr ) )
#include "ini.h"
where my_custom_malloc
and my_custom_free
are your own memory allocation/deallocation functions. The ctx
parameter
is an optional parameter of type void*
. When ini_create
or ini_load
is called, you can pass in a memctx
parameter, which can be a pointer to anything you like, and which will be passed through as the ctx
parameter to every
INI_MALLOC
/INI_FREE
call. For example, if you are doing memory tracking, you can pass a pointer to your tracking
data as memctx
, and in your custom allocation/deallocation function, you can cast the ctx
param back to the
right type, and access the tracking data.
If no custom allocator is defined, ini.h will default to malloc
and free
from the C runtime library.
The library makes use of three additional functions from the C runtime library, and for full flexibility, it allows you to substitute them for your own. Here's an example:
#define INI_IMPLEMENTATION
#define INI_MEMCPY( dst, src, cnt ) ( my_memcpy_func( dst, src, cnt ) )
#define INI_STRLEN( s ) ( my_strlen_func( s ) )
#define INI_STRICMP( s1, s2 ) ( my_stricmp_func( s1, s2 ) )
#include "ini.h"
If no custom function is defined, ini.h will default to the C runtime library equivalent.
ini_t* ini_create( void* memctx )
Instantiates a new, empty ini structure, which can be manipulated with other API calls, to fill it with data. To save it
out to an ini-file string, use ini_save
. When no longer needed, it can be destroyed by calling ini_destroy
.
memctx
is a pointer to user defined data which will be passed through to the custom INI_MALLOC/INI_FREE calls. It can
be NULL if no user defined data is needed.
ini_t* ini_load( char const* data, void* memctx )
Parse the zero-terminated string data
containing an ini-file, and create a new ini_t instance containing the data.
The instance can be manipulated with other API calls to enumerate sections/properties and retrieve values. When no
longer needed, it can be destroyed by calling ini_destroy
. memctx
is a pointer to user defined data which will be
passed through to the custom INI_MALLOC/INI_FREE calls. It can be NULL if no user defined data is needed.
int ini_save( ini_t const* ini, char* data, int size )
Saves an ini structure as a zero-terminated ini-file string, into the specified buffer. Returns the number of bytes
written, including the zero terminator. If data
is NULL, nothing is written, but ini_save
still returns the number
of bytes it would have written. If the size of data
, as specified in the size
parameter, is smaller than that
required, only part of the ini-file string will be written. ini_save
still returns the number of bytes it would have
written had the buffer been large enough.
void ini_destroy( ini_t* ini )
Destroy an ini_t
instance created by calling ini_load
or ini_create
, releasing the memory allocated by it. No
further API calls are valid on an ini_t
instance after calling ini_destroy
on it.
int ini_section_count( ini_t const* ini )
Returns the number of sections in an ini file. There's at least one section in an ini file (the global section), but there can be many more, each specified in the file by the section name wrapped in square brackets [ ].
char const* ini_section_name( ini_t const* ini, int section )
Returns the name of the section with the specified index. section
must be non-negative and less than the value
returned by ini_section_count
, or ini_section_name
will return NULL. The defined constant INI_GLOBAL_SECTION
can
be used to indicate the global section.
int ini_property_count( ini_t const* ini, int section )
Returns the number of properties belonging to the section with the specified index. section
must be non-negative and
less than the value returned by ini_section_count
, or ini_section_name
will return 0. The defined constant
INI_GLOBAL_SECTION
can be used to indicate the global section. Properties are declared in the ini-file on he format
name=value
.
char const* ini_property_name( ini_t const* ini, int section, int property )
Returns the name of the property with the specified index property
in the section with the specified index section
.
section
must be non-negative and less than the value returned by ini_section_count
, and property
must be
non-negative and less than the value returned by ini_property_count
, or ini_property_name
will return NULL. The
defined constant INI_GLOBAL_SECTION
can be used to indicate the global section.
char const* ini_property_value( ini_t const* ini, int section, int property )
Returns the value of the property with the specified index property
in the section with the specified index section
.
section
must be non-negative and less than the value returned by ini_section_count
, and property
must be
non-negative and less than the value returned by ini_property_count
, or ini_property_value
will return NULL. The
defined constant INI_GLOBAL_SECTION
can be used to indicate the global section.
int ini_find_section( ini_t const* ini, char const* name, int name_length )
Finds the section with the specified name, and returns its index. name_length
specifies the number of characters in
name
, which does not have to be zero-terminated. If name_length
is zero, the length is determined automatically, but
in this case name
has to be zero-terminated. If no section with the specified name could be found, the value
INI_NOT_FOUND
is returned.
int ini_find_property( ini_t const* ini, int section, char const* name, int name_length )
Finds the property with the specified name, within the section with the specified index, and returns the index of the
property. name_length
specifies the number of characters in name
, which does not have to be zero-terminated. If
name_length
is zero, the length is determined automatically, but in this case name
has to be zero-terminated. If no
property with the specified name could be found within the specified section, the value INI_NOT_FOUND
is returned.
section
must be non-negative and less than the value returned by ini_section_count
, or ini_find_property
will
return INI_NOT_FOUND
. The defined constant INI_GLOBAL_SECTION
can be used to indicate the global section.
int ini_section_add( ini_t* ini, char const* name, int length )
Adds a section with the specified name, and returns the index it was added at. There is no check done to see if a
section with the specified name already exists - multiple sections of the same name are allowed. length
specifies the
number of characters in name
, which does not have to be zero-terminated. If length
is zero, the length is determined
automatically, but in this case name
has to be zero-terminated.
void ini_property_add( ini_t* ini, int section, char const* name, int name_length, char const* value, int value_length )
Adds a property with the specified name and value to the specified section, and returns the index it was added at. There
is no check done to see if a property with the specified name already exists - multiple properties of the same name are
allowed. name_length
and value_length
specifies the number of characters in name
and value
, which does not have
to be zero-terminated. If name_length
or value_length
is zero, the length is determined automatically, but in this
case name
/value
has to be zero-terminated. section
must be non-negative and less than the value returned by
ini_section_count
, or the property will not be added. The defined constant INI_GLOBAL_SECTION
can be used to
indicate the global section.
void ini_section_remove( ini_t* ini, int section )
Removes the section with the specified index, and all properties within it. section
must be non-negative and less than
the value returned by ini_section_count
. The defined constant INI_GLOBAL_SECTION
can be used to indicate the global
section. Note that removing a section will shuffle section indices, so that section indices you may have stored will no
longer indicate the same section as it did before the remove. Use the find functions to update your indices.
void ini_property_remove( ini_t* ini, int section, int property )
Removes the property with the specified index from the specified section. section
must be non-negative and less than
the value returned by ini_section_count
, and property
must be non-negative and less than the value returned by
ini_property_count
. The defined constant INI_GLOBAL_SECTION
can be used to indicate the global section. Note that
removing a property will shuffle property indices within the specified section, so that property indices you may have
stored will no longer indicate the same property as it did before the remove. Use the find functions to update your
indices.
void ini_section_name_set( ini_t* ini, int section, char const* name, int length )
Change the name of the section with the specified index. section
must be non-negative and less than the value returned
by ini_section_count
. The defined constant INI_GLOBAL_SECTION
can be used to indicate the global section. length
specifies the number of characters in name
, which does not have to be zero-terminated. If length
is zero, the length
is determined automatically, but in this case name
has to be zero-terminated.
void ini_property_name_set( ini_t* ini, int section, int property, char const* name, int length )
Change the name of the property with the specified index in the specified section. section
must be non-negative and
less than the value returned by ini_section_count
, and property
must be non-negative and less than the value
returned by ini_property_count
. The defined constant INI_GLOBAL_SECTION
can be used to indicate the global section.
length
specifies the number of characters in name
, which does not have to be zero-terminated. If length
is zero,
the length is determined automatically, but in this case name
has to be zero-terminated.
void ini_property_value_set( ini_t* ini, int section, int property, char const* value, int length )
Change the value of the property with the specified index in the specified section. section
must be non-negative and
less than the value returned by ini_section_count
, and property
must be non-negative and less than the value
returned by ini_property_count
. The defined constant INI_GLOBAL_SECTION
can be used to indicate the global section.
length
specifies the number of characters in value
, which does not have to be zero-terminated. If length
is zero,
the length is determined automatically, but in this case value
has to be zero-terminated.