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.