The extent of a configuration file is not limited to .conf
, can also be .cnf
, .conf
, .cfg
, or .ini
for example. There is no pattern of how a configuration file can be called.
It is possible to read it manually, but it is a somewhat laborious task, you can use the fopen
to open the file for reading, fgets
to read line by line, and the sscanf
to analyze the line and get the values.
This approach may be a bit limited, it may work in certain situations where you know the file structure, but it may fail if you have an extra space or line. See here an implementation.
In Windows it is possible to use Apis GetPrivateProfileString
to return a value, GetPrivateProfileInt
to return an integer and GetPrivateProfileSection
to return the keys and values of a section.
To Qt it is possible to use class functions QSettings
.
There is no native option to read a configuration file, but there are alternatives like:
- Libconfig: C/C++. Available for GNU/Linux, Mac OS X, Solaris, Freebsd, Android, and Windows. Documentation.
- Libini: C, C++, Visual Basic, Java, TCL, Perl, Python. Available for Windows, DOS, GNU/Linux.
- libConfuse: C. Like the others above, it is also available for Windows and Unix-based systems. Tutorial.
- inih: C/C++. Designed to be lightweight and simple, the developer of this project seems to have prioritized this to be compatible with embedded systems.
- Among others...
To create an example I will use the inih, the code is an adaptation of that example of documentation.
Assuming you have a configuration file foo.cfg
as below:
; Exemplo de arquivo de configuração
[usuario]
nome = João Silva ; Os espaços entre "=" são removidos
peso = 90.5 ; Valor de ponto flutuante
idade = 100 ; Valor inteiro
ativo = true ; Valor booleano
[local]
cidade = Rio Branco ; Os comentários serão ignorados (como esse)
estado = Acre
To save the information that will be read from the file, we will use the structure below:
typedef struct {
const char* nome;
float peso;
int idade;
bool ativo;
const char* cidade;
const char* estado;
} configuracao;
As mentioned in documentation, use a Handler to identify the section and key and store the value in the structure. The Handler/callback is called every time a couple of chave=valor
is analyzed. In this example, we can do so:
static int handler(void* usuario, const char* secao, const char* nome, const char* valor)
{
configuracao* cfg = (configuracao*)usuario;
#define MATCH(s, n) strcmp(secao, s) == 0 && strcmp(nome, n) == 0
/* Identifica a seção e chave e guarda seu valor na estrutura */
if (MATCH("usuario", "nome")) {
cfg->nome = strdup(valor);
} else if (MATCH("usuario", "peso")) {
cfg->peso = atof(valor);
} else if (MATCH("usuario", "idade")) {
cfg->idade = atoi(valor);
} else if (MATCH("usuario", "ativo")) {
cfg->ativo = (bool)valor;
} else if (MATCH("local", "cidade")) {
cfg->cidade = strdup(valor);
} else if (MATCH("local", "estado")) {
cfg->estado = strdup(valor);
} else {
return 0; /* Seção desconhecida ou chave inválida */
}
return 1;
}
Finally, in the main function of the program, main()
, you use the function ini_parse
to load the configuration file:
int main(int argc, char* argv[])
{
configuracao cfg;
if (ini_parse("foo.cfg", handler, &cfg) < 0) {
printf("Não foi possível carregar 'foo.cfg'\n");
return 1;
}
printf("Configurações carregadas do arquivo 'foo.cfg'\n");
printf("Nome: %s\nPeso: %f\nIdade: %d\nAtivo: %d\n", cfg.nome, cfg.peso,
cfg.idade, cfg.ativo);
printf("Cidade: %s, Estado: %s\n", cfg.cidade, cfg.estado);
return 0;
}
The whole code goes like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include ".ini.h" /* Assumindo que o header esteja no mesmo diretório */
typedef struct {
const char* nome;
float peso;
int idade;
bool ativo;
const char* cidade;
const char* estado;
} configuracao;
static int handler(void* usuario, const char* secao, const char* nome, const char* valor) {
configuracao* cfg = (configuracao*)usuario;
#define MATCH(s, n) strcmp(secao, s) == 0 && strcmp(nome, n) == 0
if (MATCH("usuario", "nome")) {
cfg->nome = strdup(valor);
} else if (MATCH("usuario", "peso")) {
cfg->peso = atof(valor);
} else if (MATCH("usuario", "idade")) {
cfg->idade = atoi(valor);
} else if (MATCH("usuario", "ativo")) {
cfg->ativo = (bool)valor;
} else if (MATCH("local", "cidade")) {
cfg->cidade = strdup(valor);
} else if (MATCH("local", "estado")) {
cfg->estado = strdup(valor);
} else {
return 0; /* Seção desconhecida ou chave inválida */
}
return 1;
}
int main(int argc, char* argv[])
{
configuracao cfg;
if (ini_parse("foo.cfg", handler, &cfg) < 0) {
printf("Não foi possível carregar 'foo.cfg'\n");
return 1;
}
printf("Configurações carregadas do arquivo 'foo.cfg'\n");
printf("Nome: %s\nPeso: %f\nIdade: %d\nAtivo: %d\n", cfg.nome, cfg.peso,
cfg.idade, cfg.ativo);
printf("Cidade: %s, Estado: %s\n", cfg.cidade, cfg.estado);
return 0;
}
Demonstration:
$ gcc -o bar main.c ini.c
$ ./bar
Configurações carregadas do arquivo 'foo.cfg'
Nome: João Silva
Peso: 90.500000
Idade: 100
Ativo: 1
Cidade: Rio Branco, Estado: Acre
$
Really, I need agility.... this is all ready....
– Roberval Sena 山本
What fun! after your post, other friends changed their posts a little! Like, they took away the part "Be afraid to do everything by hand, and it’ll be hard work..." for .. " Ta check options around!!! " Is that the group that reads the posts... also... gives a read in the editions???? before giving positive to the gallery?
– Roberval Sena 山本