ini Reader
In diesem Tutorial wird beschrieben, wie wir aus einer ini Datei Konfigurationseinstellungen laden können.
In der ini Datei werden wir später Einstellungen für z.B. die Fenster Höhe und Breite speichern. Dieser Code ist nicht von C++ Development entwickelt sondern von Google kopiert! Quelle: Link
Es müssen folgende Dateien angelegt werden:
Datei:
Headerdateien/ini.h- #ifndef __INI_H__
- #define __INI_H__
- #ifdef __cplusplus
- extern "C" {
- #endif
-
- #include <stdio.h>
-
- int ini_parse(const char* filename,
- int(*handler)(void* user, const char* section,
- const char* name, const char* value),
- void* user);
-
- int ini_parse_file(FILE* file,
- int(*handler)(void* user, const char* section,
- const char* name, const char* value),
- void* user);
-
- #ifndef INI_ALLOW_MULTILINE
- #define INI_ALLOW_MULTILINE 1
- #endif
-
- #ifndef INI_ALLOW_BOM
- #define INI_ALLOW_BOM 1
- #endif
-
- #ifndef INI_USE_STACK
- #define INI_USE_STACK 1
- #endif
-
- #ifndef INI_STOP_ON_FIRST_ERROR
- #define INI_STOP_ON_FIRST_ERROR 0
- #endif
-
- #ifndef INI_MAX_LINE
- #define INI_MAX_LINE 200
- #endif
-
- #ifdef __cplusplus
- }
- #endif
-
- #endif
Datei:
Quelldateien/ini.cpp- #include <stdio.h>
- #include <ctype.h>
- #include <string.h>
- #include "ini.h"
-
- #if !INI_USE_STACK
- #include <stdlib.h>
- #endif
-
- #define MAX_SECTION 50
- #define MAX_NAME 50
-
- static char* rstrip(char* s)
- {
- char* p = s + strlen(s);
- while (p > s && isspace((unsigned char)(*--p)))
- *p = '\0';
- return s;
- }
-
- static char* lskip(const char* s)
- {
- while (*s && isspace((unsigned char)(*s)))
- s++;
- return (char*)s;
- }
-
- static char* find_char_or_comment(const char* s, char c)
- {
- int was_whitespace = 0;
- while (*s && *s != c && !(was_whitespace && *s == ';')) {
- was_whitespace = isspace((unsigned char)(*s));
- s++;
- }
- return (char*)s;
- }
-
- static char* strncpy0(char* dest, const char* src, size_t size)
- {
- strncpy(dest, src, size);
- dest[size - 1] = '\0';
- return dest;
- }
-
- int ini_parse_file(FILE* file,
- int(*handler)(void*, const char*, const char*,
- const char*),
- void* user)
- {
-
- #if INI_USE_STACK
- char line[INI_MAX_LINE];
- #else
- char* line;
- #endif
- char section[MAX_SECTION] = "";
- char prev_name[MAX_NAME] = "";
-
- char* start;
- char* end;
- char* name;
- char* value;
- int lineno = 0;
- int error = 0;
-
- #if !INI_USE_STACK
- line = (char*)malloc(INI_MAX_LINE);
- if (!line) {
- return -2;
- }
- #endif
-
- /* Scan through file line by line */
- while (fgets(line, INI_MAX_LINE, file) != NULL) {
- lineno++;
-
- start = line;
- #if INI_ALLOW_BOM
- if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
- (unsigned char)start[1] == 0xBB &&
- (unsigned char)start[2] == 0xBF) {
- start += 3;
- }
- #endif
- start = lskip(rstrip(start));
-
- if (*start == ';' || *start == '#') {
- /* Per Python ConfigParser, allow '#' comments at start of line */
- }
- #if INI_ALLOW_MULTILINE
- else if (*prev_name && *start && start > line) {
- /* Non-black line with leading whitespace, treat as continuation
- of previous name's value (as per Python ConfigParser). */
- if (!handler(user, section, prev_name, start) && !error)
- error = lineno;
- }
- #endif
- else if (*start == '[') {
- /* A "[section]" line */
- end = find_char_or_comment(start + 1, ']');
- if (*end == ']') {
- *end = '\0';
- strncpy0(section, start + 1, sizeof(section));
- *prev_name = '\0';
- }
- else if (!error) {
- /* No ']' found on section line */
- error = lineno;
- }
- }
- else if (*start && *start != ';') {
- /* Not a comment, must be a name[=:]value pair */
- end = find_char_or_comment(start, '=');
- if (*end != '=') {
- end = find_char_or_comment(start, ':');
- }
- if (*end == '=' || *end == ':') {
- *end = '\0';
- name = rstrip(start);
- value = lskip(end + 1);
- end = find_char_or_comment(value, '\0');
- if (*end == ';')
- *end = '\0';
- rstrip(value);
-
- /* Valid name[=:]value pair found, call handler */
- strncpy0(prev_name, name, sizeof(prev_name));
- if (!handler(user, section, name, value) && !error)
- error = lineno;
- }
- else if (!error) {
- /* No '=' or ':' found on name[=:]value line */
- error = lineno;
- }
- }
-
- #if INI_STOP_ON_FIRST_ERROR
- if (error)
- break;
- #endif
- }
-
- #if !INI_USE_STACK
- free(line);
- #endif
-
- return error;
- }
-
- int ini_parse(const char* filename,
- int(*handler)(void*, const char*, const char*, const char*),
- void* user)
- {
- FILE* file;
- int error;
-
- file = fopen(filename, "r");
- if (!file)
- return -1;
- error = ini_parse_file(file, handler, user);
- fclose(file);
- return error;
- }
-
Datei:
Headerdateien/INIReader.h- #ifndef __INIREADER_H__
- #define __INIREADER_H__
- #include <map>
- #include <string>
- class INIReader
- {
- public:
- INIReader(std::string filename);
- int ParseError();
- std::string GetString(std::string section, std::string name, std::string default_value);
- long GetInteger(std::string section, std::string name, long default_value);
- double GetDouble(std::string section, std::string name, double default_value);
- bool GetBoolean(std::string section, std::string name, bool default_value);
-
- private:
- int _error;
- std::map<std::string, std::string> _values;
- static std::string MakeKey(std::string section, std::string name);
- static int ValueHandler(void* user, const char* section, const char* name, const char* value);
- };
- #endif
Datei:
Quelldateien/INIReader.cpp- #include <algorithm>
- #include <cctype>
- #include <cstdlib>
- #include "ini.h"
- #include "INIReader.h"
-
- using std::string;
-
- INIReader::INIReader(string filename)
- {
- _error = ini_parse(filename.c_str(), ValueHandler, this);
- }
-
- int INIReader::ParseError()
- {
- return _error;
- }
-
- string INIReader::GetString(string section, string name, string default_value)
- {
- string key = MakeKey(section, name);
- return _values.count(key) ? _values[key] : default_value;
- }
-
- long INIReader::GetInteger(string section, string name, long default_value)
- {
- string valstr = GetString(section, name, "");
- const char* value = valstr.c_str();
- char* end;
- long n = strtol(value, &end, 0);
- return end > value ? n : default_value;
- }
-
- double INIReader::GetDouble(string section, string name, double default_value)
- {
- string valstr = GetString(section, name, "");
- const char* value = valstr.c_str();
- char* end;
- double n = strtod(value, &end);
- return end > value ? n : default_value;
- }
-
- bool INIReader::GetBoolean(string section, string name, bool default_value)
- {
- string valstr = GetString(section, name, "");
- std::transform(valstr.begin(), valstr.end(), valstr.begin(), ::tolower);
- if (valstr == "true" || valstr == "yes" || valstr == "on" || valstr == "1")
- return true;
- else if (valstr == "false" || valstr == "no" || valstr == "off" || valstr == "0")
- return false;
- else
- return default_value;
- }
-
- string INIReader::MakeKey(string section, string name)
- {
- string key = section + "." + name;
- std::transform(key.begin(), key.end(), key.begin(), ::tolower);
- return key;
- }
-
- int INIReader::ValueHandler(void* user, const char* section, const char* name, const char* value)
- {
- INIReader* reader = (INIReader*)user;
- string key = MakeKey(section, name);
- if (reader->_values[key].size() > 0)
- reader->_values[key] += "\n";
- reader->_values[key] += value;
- return 1;
- }
-
-
Nach dem Einbinden der notwendigen Daten können wir nun auf die Header Dateien verlinken und ini Dateien einlesen. Zuerst sollte aber noch die ini Datei mit folgendem Inhalt erstellt werden und im Projekt Ordner gespeichert werden.
Datei:
config.ini- ; Konfigurationsdatei
- [protocol]
- version = 0xFF ; int sowie hex erlaubt
- # gespeicherte einstellungen
- [user]
- name = Johnny Wayne
- email = johnny@gmx.de
- active = true
- pi = 3.141592
Datei:
Quelldateien/main.cpp- #include <iostream> // std::cout, std::endl, std::cin
- #include <stdlib.h> // EXIT_SUCCESS, EXIT_FAILURE
- #include "INIReader.h"
-
- int main(void)
- {
- std::cout << "ini files einlesen\n" << std::endl;
- INIReader ini("config.ini");
- if (ini.ParseError() < 0)
- {
- std::cerr << "Can't load 'config.ini'\n";
- return EXIT_FAILURE;
- }
- std::cout << "version=" << ini.GetInteger("protocol", "version", -1) << std::endl;
- std::cout << "name=" << ini.GetString("user", "name", "UNKNOWN") << std::endl;
- std::cout << "email=" << ini.GetString("user", "email", "UNKNOWN") << std::endl;
- std::cout << "pi=" << ini.GetDouble("user", "pi", -1) << std::endl;
- std::cout << "active=" << ini.GetBoolean("user", "active", true) << "\n\n";
-
- std::cin.get();
- return EXIT_SUCCESS;
- }
Mit "ini.GetInteger("protocol", "version", -1)" laden wir unter der Sektion protocol denn Eintrag version. Das -1 bedeutet, dass -1 zurück gegeben wird wenn der gesuchte Eintrag nicht vorhanden ist! Es können Strings, Integer Double und Boolean Werte gelesen werden. Zu beachten ist noch, dass in der ini Datei z.B. vor version keine Leerzeichen sein dürfen, da der Eintrag sonst nicht gefunden wird!