Ich brauchte neulich wieder irgendeine einfache Konfigurationsdatei. Einfach um ein paar Variablen zu definieren, bei denen ich mein Programm nicht ständig neu kompilieren muss, wenn ich sie ändern will. Textbasiert musste es sein, damit man es einfach editieren kann. Mein erster Impuls war also XML, aber seien wir ehrlich, die Syntax von XML ist grauenhaft, sowas will man weder schreiben noch lesen. Weitere Alternativen waren JSON und Yaml. Beides hab ich nicht benutzt, letzteres schien mir aber eine verbesserte Version von ersterem zu sein. Also habe ich die nächstbeste YAML Bibliothek installiert und losgelegt. Und schnell wieder aufgehört, weil yamlcpp alles andere als einfach zu benutzen war. Es fängt schon damit an, dass die CMake Datei über 300 Zeilen hat (wieso zur Hölle kann es so kompliziert sein, eine Bibliothek zu kompilieren, die Textdateien verarbeitet, dass man ein 300 Zeilen Programm schreiben muss das Projektdateien generiert???). Nachdem diese Hürde genommen war, stoplerte ich aber ANDAUERND über Syntax-Fehler die schwer zu beheben waren, da die Fehlerausgabe von Yamlcpp unter aller Sau ist. Kurz ich hatte keinen Bock mehr.
Dann habe ich mir gesagt "Das Problem ist doch echt nicht so schwer, ich wette ich kann einen Loader schreiben, der mit weniger Code als die CMake-Datei von yamlcpp auskommt, und alles kann was ich will". Es stellte sich heraus, dass ich recht hatte.
Was soll das ganze?
Möglichst einfaches auslesen nett strukturierter Textdateien. Beispiel:
(Sieht besser aus, wenn ein Tab 4 Leerzeichen groß ist, weiß grad nicht wie man es umstellt. Oder wer denkt, 8 Leerzeichen wäre eine sinnvolle Tabulator-Größe...)
Code: Alles auswählen
Scene
Camera
Position = 10 12 14
Focal Length = 10.4
Model = PMD SuperCam
New = false
Objects
Table
Height = 4
Shininess = 0
Ball
Radius = 3
Files
SaveTo = C:\LabData\Files.txd
overwrite
noWarnings
Dependencys
C:\Standard Resources\Ball
C:\Standard Resources\Table
Einlesen:
Code: Alles auswählen
#include <iostream>
#include "TexData.hpp"
using namespace std;
int main()
{
try
{
auto config = TexData::LoadFile("test.txt");
config.DebugPrint();
cout << "\n\n" << config["Scene"]["Files"]["SaveTo"].as<string>() << endl;
for(auto& c : config["Scene"]["Dependencys"])
{
cout << c->as<string>() << endl;
}
auto Scene = config["Scene"];
cout << "Overwrite: " << Scene["Files"].has("overwrite") << endl;
}
catch(std::exception& ex)
{
cout << ex.what() << endl;
}
system("pause");
}
Warum ist das toll?
Weil man ständig simple Konfigurationsdateien braucht. Weil man zum Installieren nur 2 kleine Dateien in sein Projekt kopieren muss (angenommen, man verwendet schon boost). Und weil man dann Variablen in einer einzigen Zeile, mir einer relativ hübschen Syntax auslesen kann (TexData::LoadFile("test.txt")["Scene"]["Files"]["SaveTo"].Value()). Und weil man, wenn man irgendetwas falsch macht, eine Fehlermeldung bekommt, die einem genau sagt, was schief gelaufen ist, und wo. Und weil der Code nur 356 Zeilen hat, inklusive geräumiger Formatierung und Kommentaren und man es deshalb leicht verstehen und erweitern kann. KISS.
Aber ernsthaft noch ein Format?
Ja, denn: TexData ist sehr simpel. Es ist nicht für jede Art von Daten gedacht, sondern eher für Konfigurationsdateien und ähnliches. Es gibt keine direkte Unterstützung für komplexe Datentypen (man kann alle Typen benutzen, die man in einen 1-Zeilen String hin- und zurück casten kann), also keine Arrays, Listen oder Binärdaten. Aber dafür ist es sehr einfach zu benutzen. Ein Nischenformat also, aber eines das ich schon in viele meiner Projekte eingebaut habe, weil es so leicht geht und so nützlich ist.
Lizenz:
Naja, es sind ~350 nicht sehr geistreiche Zeilen. Benutzt sie, erweitert sie und schreibt mir, wenns euch gefallen hat. Möglicherweise bau ich irgendewann mehr Features ein und lade irgendwo ein Git-Repository hoch, mal sehen.