inih (INI Not Invented Here) é um analisador de arquivo .INI simples escrito em C. São apenas algumas páginas de código e foi projetado para ser pequeno e simples , por isso é bom para sistemas embarcados. Também é mais ou menos compatível com o estilo ConfigParser de arquivos .INI do Python, incluindo sintaxe multilinha no estilo RFC 822 e entradas de name: value
.
Para usá-lo, basta fornecer ini_parse()
um arquivo INI e ele chamará um retorno de chamada para cada name=value
analisado, fornecendo strings para a seção, nome e valor. Isso é feito dessa maneira ("estilo SAX") porque funciona bem em sistemas embarcados com pouca memória, mas também porque é uma implementação KISS.
Você também pode chamar ini_parse_file()
para analisar diretamente de um objeto FILE*
, ini_parse_string()
para analisar dados de uma string ou ini_parse_stream()
para analisar usando uma função de leitor personalizada no estilo fgets para E/S personalizada.
Baixe uma versão, navegue na fonte ou leia sobre como usar o inih no estilo DRY com X-Macros.
Você pode controlar vários aspectos do inih usando definições de pré-processador:
-DINI_ALLOW_MULTILINE=0
.-DINI_ALLOW_BOM=0
.;
personagem. Para desabilitar, adicione -DINI_ALLOW_INLINE_COMMENTS=0
. Você também pode especificar quais caracteres iniciam um comentário embutido usando INI_INLINE_COMMENT_PREFIXES
.;
e #
para iniciar um comentário no início de uma linha. Você pode substituir isso alterando INI_START_COMMENT_PREFIXES
.=
ou :
na linha) como um erro. Para permitir nomes sem valores, adicione -DINI_ALLOW_NO_VALUE=1
e inih chamará sua função de manipulador com valor definido como NULL.-DINI_STOP_ON_FIRST_ERROR=1
.ini_handler
não recebe o número da linha como parâmetro. Se precisar disso, adicione -DINI_HANDLER_LINENO=1
.name=value
. Para detectar novas seções (por exemplo, o arquivo INI possui múltiplas seções com o mesmo nome), adicione -DINI_CALL_HANDLER_ON_NEW_SECTION=1
. Sua função de manipulador será então chamada cada vez que uma nova seção for encontrada, com section
definida como o nome da nova seção, mas name
e value
definidos como NULL.malloc
, especifique -DINI_USE_STACK=0
.-DINI_MAX_LINE=1000
. Observe que INI_MAX_LINE
deve ser 3 a mais que a linha mais longa (devido a r
, n
e ao NUL).INI_INITIAL_ALLOC
especifica o tamanho inicial do malloc ao usar o heap. O padrão é 200 bytes.-DINI_USE_STACK=0
), inih aloca um buffer de tamanho fixo de bytes INI_INITIAL_ALLOC
. Para permitir que isso cresça para bytes INI_MAX_LINE
, dobrando se necessário, defina -DINI_ALLOW_REALLOC=1
.malloc
, free
e realloc
da biblioteca padrão são usadas; para usar um alocador personalizado, especifique -DINI_CUSTOM_ALLOCATOR=1
(e -DINI_USE_STACK=0
). Você deve definir e vincular funções denominadas ini_malloc
, ini_free
e (se INI_ALLOW_REALLOC
estiver definido) ini_realloc
, que devem ter as mesmas assinaturas que as funções de alocação de memória stdlib.h
. #include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "../ini.h"
typedef struct
{
int version ;
const char * name ;
const char * email ;
} configuration ;
static int handler ( void * user , const char * section , const char * name ,
const char * value )
{
configuration * pconfig = ( configuration * ) user ;
#define MATCH ( s , n ) strcmp(section, s) == 0 && strcmp(name, n) == 0
if ( MATCH ( "protocol" , "version" )) {
pconfig -> version = atoi ( value );
} else if ( MATCH ( "user" , "name" )) {
pconfig -> name = strdup ( value );
} else if ( MATCH ( "user" , "email" )) {
pconfig -> email = strdup ( value );
} else {
return 0 ; /* unknown section/name, error */
}
return 1 ;
}
int main ( int argc , char * argv [])
{
configuration config ;
if ( ini_parse ( "test.ini" , handler , & config ) < 0 ) {
printf ( "Can't load 'test.ini'n" );
return 1 ;
}
printf ( "Config loaded from 'test.ini': version=%d, name=%s, email=%sn" ,
config . version , config . name , config . email );
return 0 ;
}
Se você gosta de C++ e STL, há também uma classe INIReader fácil de usar que armazena valores em um map
e permite que você os Get()
:
# include < iostream >
# include " INIReader.h "
int main ()
{
INIReader reader ( " ../examples/test.ini " );
if (reader. ParseError () < 0 ) {
std::cout << " Can't load 'test.ini' n " ;
return 1 ;
}
std::cout << " Config loaded from 'test.ini': version= "
<< reader. GetInteger ( " protocol " , " version " , - 1 ) << " , name= "
<< reader. Get ( " user " , " name " , " UNKNOWN " ) << " , email= "
<< reader. Get ( " user " , " email " , " UNKNOWN " ) << " , pi= "
<< reader. GetReal ( " user " , " pi " , - 1 ) << " , active= "
<< reader. GetBoolean ( " user " , " active " , true ) << " n " ;
return 0 ;
}
Esta API C++ simples funciona bem, mas não é totalmente desenvolvida. Não estou planejando trabalhar mais na API C++ no momento, então se você quiser um pouco mais de poder (por exemplo, funções GetSections()
e GetFields()
), veja estes forks:
Algumas diferenças entre o inih e o módulo de biblioteca padrão ConfigParser do Python:
_wfopen()
para abrir um arquivo e então ini_parse_file()
para analisá-lo; inih não inclui manipulação wchar_t
ou Unicode. meson.build
não é necessário para usar ou compilar o inih, seu objetivo principal é para distribuições.-Ddefault_library=static
bibliotecas estáticas são construídas.-Ddistro_install=false
bibliotecas, cabeçalhos e arquivos pkg-config não serão instalados.-Dwith_INIReader=false
você pode desabilitar a construção da biblioteca C++.distro_install
estiver definido como true
.inih
e INIReader
.inih_dep
e INIReader_dep
. Você pode querer definir default_library=static
e distro_install=false
para o subprojeto. Um Wrap oficial é fornecido no WrapDB.version : '<version_as_int>',
após a tag license
na função project()
e version : meson.project_version(),
após a tag soversion
em ambas as funções library()
. inih
pode ser facilmente usado em projetos tipi.build simplesmente adicionando a seguinte entrada ao seu .tipi/deps
(substitua r56
pela tag de versão mais recente):
{
"benhoyt/inih" : { "@" : " r56 " }
}
O caminho de inclusão obrigatório em seu projeto é:
#include <ini.h>
Você pode construir e instalar o inih usando o gerenciador de dependências vcpkg:
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install inih
A porta inih no vcpkg é mantida atualizada pelos membros da equipe da Microsoft e colaboradores da comunidade. Se a versão estiver desatualizada, crie um problema ou solicitação pull no repositório vcpkg.