How to Create and read ". conf" files in C, for linux environment?

Asked

Viewed 1,883 times

8

I’m studying C in linux environment.

I have a problem in how to create a configuration file for my program to know what to do when running.

Question

  • Does anyone know how to store and read variables in files .conf?
  • There’s a technique to it?
  • What is the standard?

3 answers

13

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.

  1. 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
    
  2. 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;
    
  3. 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;
    }
    
  4. 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
$

3

There are several ways to create configuration files. The configuration files in /etc has its own structure for the user to read.

If you just want to store the values of your variables in the files, so that only the system reads, you can use the fwrite and the fread.

This method is only for saving system information, in case you try to edit the file in hand, it may give some error and the system may load the information wrong way.

#include <stdio.h>
#include <string.h>

struct _config{
    char string[16];
    int number;
    float o_number;
    char name[32];
};

void write_config(const char *fd_conf, struct _config *cfg){
    FILE *f = fopen(fd_conf, "w");
    fwrite(cfg, sizeof(struct _config), 1, f);
    fclose(f);
}

void read_config(const char *fd_conf, struct _config *cfg){
    FILE *f = fopen(fd_conf, "r");
    fread(cfg, sizeof(struct _config), 1, f);
    fclose(f);
}

int main(int argc, char **argv){
    struct _config conf = {0};
    conf.number = 10;
    conf.o_number = 3.7f;
    strcpy(conf.string, "texto");
    strcpy(conf.name, "I am a user!");

    write_config("file.cfg", &conf);

    struct _config conf2 = {0};
    read_config("file.cfg", &conf2);

    printf("%d|%f|%s|%s\n",conf2.number, conf2.o_number, conf.string, conf2.name);

    return 0;
}

2


Use the confusing Lib, it’s all set... it’s just magical... here is the original link of the: https://www.vivaolinux.com.br/artigo/Criando-programas-com-suporte-a-arquivos-de-configuracao-com-a-libConfuse?pagina=5

can download direct from their link:

http://savannah.nongnu.org/download/confuse/

install me facil:

$ ./configure
$ make
$ su -c 'make install'

if you are not in dir /usr/include, copy:

$ cd src/
$ su -c 'cp confuse.h /usr/include'

Look at an example of use that is in the article itself:

int main(void)
{
   int porta;
   char *servidor = NULL;
   cfg_t *cfg;
   cfg_opt_t opts[] = {
             CFG_SIMPLE_STR ("server", &servidor),
             CFG_SIMPLE_INT ("port", &porta),
             CFG_END()
             };
   cfg = cfg_init (opts, 0);
   cfg_parse (cfg, "exemplo.conf");

   printf ("\nServidor: %s \n", servidor);
   printf ("Porta: %d \n", porta);
   cfg_free(cfg);       /* Libera a memória alocada por cfg_init */
   return 0;
} 

example of . config = example.conf

 # Arquivo de configuração para teste.

server = "www.kernel.org"
port = 80

# Fim do arquivo de configuração. 
  • 1

    Really, I need agility.... this is all ready....

  • 1

    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?

Browser other questions tagged

You are not signed in. Login or sign up in order to post.