inih (INI Not Invented Here) ist ein einfacher .INI-Dateiparser, der in C geschrieben ist. Er umfasst nur ein paar Seiten Code und wurde klein und einfach konzipiert, sodass er gut für eingebettete Systeme geeignet ist. Es ist auch mehr oder weniger kompatibel mit Pythons ConfigParser-Stil von .INI-Dateien, einschließlich mehrzeiliger Syntax und name: value
Einträgen im RFC 822-Stil.
Um es zu verwenden, geben Sie ini_parse()
einfach eine INI-Datei und es ruft für jedes geparste name=value
-Paar einen Rückruf auf, der Ihnen Zeichenfolgen für den Abschnitt, den Namen und den Wert liefert. Dies geschieht auf diese Weise („SAX-Stil“), weil es auf eingebetteten Systemen mit wenig Speicher gut funktioniert, aber auch, weil es eine KISS-Implementierung ermöglicht.
Sie können auch ini_parse_file()
aufrufen, um direkt von einem FILE*
-Objekt zu analysieren, ini_parse_string()
um Daten aus einer Zeichenfolge zu analysieren, oder ini_parse_stream()
um eine benutzerdefinierte Lesefunktion im fgets-Stil für benutzerdefinierte E/A zu verwenden.
Laden Sie eine Version herunter, durchsuchen Sie die Quelle oder lesen Sie, wie Sie inih im DRY-Stil mit X-Makros verwenden.
Sie können verschiedene Aspekte von inih mithilfe von Präprozessordefinitionen steuern:
-DINI_ALLOW_MULTILINE=0
hinzu.-DINI_ALLOW_BOM=0
hinzu.;
Charakter. Zum Deaktivieren fügen Sie -DINI_ALLOW_INLINE_COMMENTS=0
hinzu. Sie können mit INI_INLINE_COMMENT_PREFIXES
auch angeben, welche(s) Zeichen einen Inline-Kommentar beginnen soll(en).;
und #
um einen Kommentar am Anfang einer Zeile zu beginnen. Sie können dies überschreiben, indem Sie INI_START_COMMENT_PREFIXES
ändern.=
oder :
in der Zeile) als Fehler. Um Namen ohne Werte zuzulassen, fügen Sie -DINI_ALLOW_NO_VALUE=1
hinzu, und inih ruft Ihre Handlerfunktion mit einem auf NULL gesetzten Wert auf.-DINI_STOP_ON_FIRST_ERROR=1
hinzu.ini_handler
-Rückruf die Zeilennummer nicht als Parameter. Wenn Sie das benötigen, fügen Sie -DINI_HANDLER_LINENO=1
hinzu.name=value
Paar auf. Um neue Abschnitte zu erkennen (z. B. wenn die INI-Datei mehrere Abschnitte mit demselben Namen enthält), fügen Sie -DINI_CALL_HANDLER_ON_NEW_SECTION=1
hinzu. Ihre Handlerfunktion wird dann jedes Mal aufgerufen, wenn ein neuer Abschnitt gefunden wird, wobei section
auf den neuen Abschnittsnamen, name
und value
jedoch auf NULL gesetzt ist.malloc
eine Zuweisung auf dem Heap vorzunehmen, geben Sie -DINI_USE_STACK=0
an.-DINI_MAX_LINE=1000
hinzu. Beachten Sie, dass INI_MAX_LINE
3 länger sein muss als die längste Zeile (aufgrund von r
, n
und dem NUL).INI_INITIAL_ALLOC
gibt die anfängliche Malloc-Größe bei Verwendung des Heaps an. Der Standardwert beträgt 200 Byte.-DINI_USE_STACK=0
) einen Puffer fester Größe mit INI_INITIAL_ALLOC
-Bytes zu. Damit dieser Wert auf INI_MAX_LINE
Bytes anwächst und sich bei Bedarf verdoppelt, legen Sie -DINI_ALLOW_REALLOC=1
fest.malloc
, free
und realloc
der Standardbibliothek verwendet; Um einen benutzerdefinierten Allokator zu verwenden, geben Sie -DINI_CUSTOM_ALLOCATOR=1
(und -DINI_USE_STACK=0
) an. Sie müssen Funktionen mit den Namen ini_malloc
, ini_free
und (wenn INI_ALLOW_REALLOC
festgelegt ist) ini_realloc
definieren und verknüpfen, die dieselben Signaturen wie die Speicherzuweisungsfunktionen stdlib.h
haben müssen. #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 ;
}
Wenn Sie sich für C++ und STL interessieren, gibt es auch eine benutzerfreundliche INIReader-Klasse, die Werte in einer map
speichert und Sie mit Get()
abrufen lässt:
# 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 ;
}
Diese einfache C++-API funktioniert gut, ist aber nicht sehr ausgereift. Ich habe im Moment nicht vor, mehr an der C++-API zu arbeiten. Wenn Sie also etwas mehr Leistung wünschen (zum Beispiel die Funktionen GetSections()
und GetFields()
), schauen Sie sich diese Forks an:
Einige Unterschiede zwischen inih und dem ConfigParser-Standardbibliotheksmodul von Python:
_wfopen()
aufrufen, um eine Datei zu öffnen, und dann ini_parse_file()
um sie zu analysieren. inih beinhaltet wchar_t
noch die Unicode-Verarbeitung. meson.build
ist für die Verwendung oder Kompilierung von inih nicht erforderlich, ihr Hauptzweck ist die Verteilung.-Ddefault_library=static
werden statische Bibliotheken erstellt.-Ddistro_install=false
werden Bibliotheken, Header und pkg-config-Dateien nicht installiert.-Dwith_INIReader=false
können Sie den Aufbau der C++-Bibliothek deaktivieren.distro_install
auf true
gesetzt ist.inih
und INIReader
.inih_dep
und INIReader_dep
verwenden. Möglicherweise möchten Sie für das Unterprojekt default_library=static
und distro_install=false
festlegen. Ein offizieller Wrap wird auf WrapDB bereitgestellt.version : '<version_as_int>',
nach dem license
Tag in der project()
-Funktion und version : meson.project_version(),
nach dem soversion
Tag in beiden library()
-Funktionen hinzu. inih
kann problemlos in tipi.build-Projekten verwendet werden, indem Sie einfach den folgenden Eintrag zu Ihrem .tipi/deps
hinzufügen (ersetzen Sie r56
durch das Tag der neuesten Version):
{
"benhoyt/inih" : { "@" : " r56 " }
}
Der erforderliche Include-Pfad in Ihrem Projekt ist:
#include <ini.h>
Sie können inih mit dem Abhängigkeitsmanager vcpkg erstellen und installieren:
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install inih
Der Inih-Port in vcpkg wird von Microsoft-Teammitgliedern und Community-Mitwirkenden auf dem neuesten Stand gehalten. Wenn die Version veraltet ist, erstellen Sie bitte einen Issue oder Pull Request im vcpkg-Repository.