Recently while workig on a project I had to parse the config from a .ini
file.
I found inih on github, a library for
parsing .ini
file in c
which is very easy to use.
It contains just two files
one is a .c
file and the other one is a .h
file. So it can be easily
put into a project
(as it does not have any other depencancy apart from c standard library).
To use inih
, get a copy of those files
$ git clone https://github.com/benhoyt/inih
$ cd inih
You will find the two files in that folder, ini.c
and ini.h
those are the
two files you will need for parsing an ini
file.
The sample .ini
file can be found in
examples of inih
.
project on github.
Although I’ll be using a different sample file in this post which is as follows.
[Section 1]
string-value = string one ; a string value
int-value = 1 ; an integer value
float-value = 2.7182 ; float value
[Section 2]
string-value = string two ; a string value
int-value = 2 ; an integer value
float-value = 1.4142 ; float value
To parse this file the code looks like.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "ini.h"
// define a structure for holding the values in "Section 1".
typedef struct{
int int_val;
float float_val;
const char* string_val;
} section_one;
// define a structure for holding the values in "Section 2".
typedef struct{
int int_val;
float float_val;
const char* string_val;
} section_two;
// define a structure for holding all of the config.
typedef struct
{
section_one s1;
section_two s2;
} configuration;
static int handler(void* config, const char* section, const char* name,
const char* value)
{
// config instance for filling in the values.
configuration* pconfig = (configuration*)config;
// define a macro for checking Sections and keys under the sections.
#define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
// fill the values in config struct for Section 1.
if(MATCH("Section 1", "string-value")){
pconfig->s1.string_val = strdup(value);
}else if(MATCH("Section 1", "int-value")){
pconfig->s1.int_val = atoi(value);
}else if(MATCH("Section 1", "float-value")){
pconfig->s1.float_val = strtof(value, NULL);
// fill the values in config struct for Section 2.
}else if(MATCH("Section 2", "string-value")){
pconfig->s2.string_val = strdup(value);
}else if(MATCH("Section 2", "int-value")){
pconfig->s2.int_val = atoi(value);
}else if(MATCH("Section 2", "float-value")){
pconfig->s2.float_val = strtof(value, NULL);
}else{
return 0;
}
return 1;
}
// function for pretty-printing.
void pp_config(configuration config){
printf("\nCONFIG---\n\n");
printf("[Section 1]\n");
printf("string-value: %s\n", config.s1.string_val);
printf("int-value: %d\n", config.s1.int_val);
printf("float-value: %f\n", config.s1.float_val);
printf("\n");
printf("[Section 2]\n");
printf("string-value: %s\n", config.s2.string_val);
printf("int-value: %d\n", config.s2.int_val);
printf("float-value: %f\n", config.s2.float_val);
}
int main(int argc, char* argv[])
{
// config for holding values.
configuration config;
// parse the .ini file
if (ini_parse("test.ini", handler, &config) < 0) {
printf("Can't load 'test.ini'\n");
return 1;
}
// print the config.
pp_config(config);
// free the memory before exiting.
free((void*)config.s1.string_val);
free((void*)config.s2.string_val);
return 0;
}
Compile the above code.
$ gcc -o parse-ini ini.c parse-ini.c
Running parse-ini
$ ./parse-ini
CONFIG---
[Section 1]
string-value: string one
int-value: 1
float-value: 2.718200
[Section 2]
string-value: string two
int-value: 2
float-value: 1.414200