inih (INI Not Invented Here) est un simple analyseur de fichiers .INI écrit en C. Il ne contient que quelques pages de code et il a été conçu pour être petit et simple , il convient donc aux systèmes embarqués. Il est également plus ou moins compatible avec le style ConfigParser de fichiers .INI de Python, y compris la syntaxe multiligne de style RFC 822 et les entrées name: value
.
Pour l'utiliser, donnez simplement ini_parse()
un fichier INI, et il appellera un rappel pour chaque paire name=value
analysée, vous donnant des chaînes pour la section, le nom et la valeur. C'est fait de cette façon ("style SAX") parce que cela fonctionne bien sur les systèmes embarqués à faible mémoire, mais aussi parce que cela permet une implémentation KISS.
Vous pouvez également appeler ini_parse_file()
pour analyser directement à partir d'un objet FILE*
, ini_parse_string()
pour analyser les données d'une chaîne, ou ini_parse_stream()
pour analyser à l'aide d'une fonction de lecteur personnalisée de style fgets pour des E/S personnalisées.
Téléchargez une version, parcourez la source ou découvrez comment utiliser inih dans un style DRY avec X-Macros.
Vous pouvez contrôler divers aspects d'inih à l'aide des définitions du préprocesseur :
-DINI_ALLOW_MULTILINE=0
.-DINI_ALLOW_BOM=0
.;
personnage. Pour désactiver, ajoutez -DINI_ALLOW_INLINE_COMMENTS=0
. Vous pouvez également spécifier quel(s) caractère(s) démarrent un commentaire en ligne à l'aide de INI_INLINE_COMMENT_PREFIXES
.;
et #
pour commencer un commentaire au début d'une ligne. Vous pouvez remplacer cela en modifiant INI_START_COMMENT_PREFIXES
.=
ou :
sur la ligne) comme une erreur. Pour autoriser les noms sans valeur, ajoutez -DINI_ALLOW_NO_VALUE=1
, et inih appellera votre fonction de gestionnaire avec une valeur définie sur NULL.-DINI_STOP_ON_FIRST_ERROR=1
.ini_handler
ne reçoit pas le numéro de ligne en tant que paramètre. Si vous en avez besoin, ajoutez -DINI_HANDLER_LINENO=1
.name=value
. Pour détecter de nouvelles sections (par exemple, le fichier INI a plusieurs sections portant le même nom), ajoutez -DINI_CALL_HANDLER_ON_NEW_SECTION=1
. Votre fonction de gestionnaire sera alors appelée chaque fois qu'une nouvelle section est rencontrée, avec section
définie sur le nouveau nom de section mais name
et value
définis sur NULL.malloc
à la place, spécifiez -DINI_USE_STACK=0
.-DINI_MAX_LINE=1000
. Notez que INI_MAX_LINE
doit être 3 de plus que la ligne la plus longue (en raison de r
, n
et de NUL).INI_INITIAL_ALLOC
spécifie la taille initiale de malloc lors de l'utilisation du tas. La valeur par défaut est 200 octets.-DINI_USE_STACK=0
), inih alloue un tampon de taille fixe d'octets INI_INITIAL_ALLOC
. Pour permettre à ce nombre d'atteindre INI_MAX_LINE
octets, en doublant si nécessaire, définissez -DINI_ALLOW_REALLOC=1
.malloc
, free
et realloc
de la bibliothèque standard sont utilisées ; pour utiliser un allocateur personnalisé, spécifiez -DINI_CUSTOM_ALLOCATOR=1
(et -DINI_USE_STACK=0
). Vous devez définir et lier des fonctions nommées ini_malloc
, ini_free
et (si INI_ALLOW_REALLOC
est défini) ini_realloc
, qui doivent avoir les mêmes signatures que les fonctions d'allocation de mémoire 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 ;
}
Si vous aimez le C++ et le STL, il existe également une classe INIReader facile à utiliser qui stocke les valeurs dans une map
et vous permet de les 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 ;
}
Cette simple API C++ fonctionne bien, mais elle n’est pas très complète. Je n'ai pas l'intention de travailler davantage sur l'API C++ pour le moment, donc si vous voulez un peu plus de puissance (par exemple les fonctions GetSections()
et GetFields()
), consultez ces forks :
Quelques différences entre inih et le module de bibliothèque standard ConfigParser de Python :
_wfopen()
pour ouvrir un fichier, puis ini_parse_file()
pour l'analyser ; inih n'inclut pas la gestion wchar_t
ou Unicode. meson.build
n'est pas nécessaire pour utiliser ou compiler inih, son objectif principal est les distributions.-Ddefault_library=static
des bibliothèques statiques sont construites.-Ddistro_install=false
les bibliothèques, les en-têtes et les fichiers pkg-config ne seront pas installés.-Dwith_INIReader=false
vous pouvez désactiver la construction de la bibliothèque C++.distro_install
est défini sur true
.inih
et INIReader
.inih_dep
et INIReader_dep
. Vous souhaiterez peut-être définir default_library=static
et distro_install=false
pour le sous-projet. Un Wrap officiel est fourni sur WrapDB.version : '<version_as_int>',
après la balise license
dans la fonction project()
et version : meson.project_version(),
après la balise soversion
dans les deux fonctions library()
. inih
peut être facilement utilisé dans les projets tipi.build en ajoutant simplement l'entrée suivante à votre .tipi/deps
(remplacez r56
par la dernière balise de version) :
{
"benhoyt/inih" : { "@" : " r56 " }
}
Le chemin d'inclusion requis dans votre projet est :
#include <ini.h>
Vous pouvez créer et installer inih à l'aide du gestionnaire de dépendances vcpkg :
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install inih
Le port inih dans vcpkg est tenu à jour par les membres de l'équipe Microsoft et les contributeurs de la communauté. Si la version est obsolète, veuillez créer un problème ou une pull request sur le référentiel vcpkg.