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.