Du bist hier: Startseite > Entwicklung (C/C++) > C++ Erweitert > ini Reader

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
  1. #ifndef __INI_H__
  2. #define __INI_H__
  3. #ifdef __cplusplus
  4. extern "C" {
  5. #endif
  6.  
  7. #include <stdio.h>
  8.  
  9. int ini_parse(const char* filename,
  10. int(*handler)(void* user, const char* section,
  11. const char* name, const char* value),
  12. void* user);
  13.  
  14. int ini_parse_file(FILE* file,
  15. int(*handler)(void* user, const char* section,
  16. const char* name, const char* value),
  17. void* user);
  18.  
  19. #ifndef INI_ALLOW_MULTILINE
  20. #define INI_ALLOW_MULTILINE 1
  21. #endif
  22.  
  23. #ifndef INI_ALLOW_BOM
  24. #define INI_ALLOW_BOM 1
  25. #endif
  26.  
  27. #ifndef INI_USE_STACK
  28. #define INI_USE_STACK 1
  29. #endif
  30.  
  31. #ifndef INI_STOP_ON_FIRST_ERROR
  32. #define INI_STOP_ON_FIRST_ERROR 0
  33. #endif
  34.  
  35. #ifndef INI_MAX_LINE
  36. #define INI_MAX_LINE 200
  37. #endif
  38.  
  39. #ifdef __cplusplus
  40. }
  41. #endif
  42.  
  43. #endif
Datei:  Quelldateien/ini.cpp
  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include <string.h>
  4. #include "ini.h"
  5.  
  6. #if !INI_USE_STACK
  7. #include <stdlib.h>
  8. #endif
  9.  
  10. #define MAX_SECTION 50
  11. #define MAX_NAME 50
  12.  
  13. static char* rstrip(char* s)
  14. {
  15. char* p = s + strlen(s);
  16. while (p > s && isspace((unsigned char)(*--p)))
  17. *p = '\0';
  18. return s;
  19. }
  20.  
  21. static char* lskip(const char* s)
  22. {
  23. while (*s && isspace((unsigned char)(*s)))
  24. s++;
  25. return (char*)s;
  26. }
  27.  
  28. static char* find_char_or_comment(const char* s, char c)
  29. {
  30. int was_whitespace = 0;
  31. while (*s && *s != c && !(was_whitespace && *s == ';')) {
  32. was_whitespace = isspace((unsigned char)(*s));
  33. s++;
  34. }
  35. return (char*)s;
  36. }
  37.  
  38. static char* strncpy0(char* dest, const char* src, size_t size)
  39. {
  40. strncpy(dest, src, size);
  41. dest[size - 1] = '\0';
  42. return dest;
  43. }
  44.  
  45. int ini_parse_file(FILE* file,
  46. int(*handler)(void*, const char*, const char*,
  47. const char*),
  48. void* user)
  49. {
  50.  
  51. #if INI_USE_STACK
  52. char line[INI_MAX_LINE];
  53. #else
  54. char* line;
  55. #endif
  56. char section[MAX_SECTION] = "";
  57. char prev_name[MAX_NAME] = "";
  58.  
  59. char* start;
  60. char* end;
  61. char* name;
  62. char* value;
  63. int lineno = 0;
  64. int error = 0;
  65.  
  66. #if !INI_USE_STACK
  67. line = (char*)malloc(INI_MAX_LINE);
  68. if (!line) {
  69. return -2;
  70. }
  71. #endif
  72.  
  73. /* Scan through file line by line */
  74. while (fgets(line, INI_MAX_LINE, file) != NULL) {
  75. lineno++;
  76.  
  77. start = line;
  78. #if INI_ALLOW_BOM
  79. if (lineno == 1 && (unsigned char)start[0] == 0xEF &&
  80. (unsigned char)start[1] == 0xBB &&
  81. (unsigned char)start[2] == 0xBF) {
  82. start += 3;
  83. }
  84. #endif
  85. start = lskip(rstrip(start));
  86.  
  87. if (*start == ';' || *start == '#') {
  88. /* Per Python ConfigParser, allow '#' comments at start of line */
  89. }
  90. #if INI_ALLOW_MULTILINE
  91. else if (*prev_name && *start && start > line) {
  92. /* Non-black line with leading whitespace, treat as continuation
  93. of previous name's value (as per Python ConfigParser). */
  94. if (!handler(user, section, prev_name, start) && !error)
  95. error = lineno;
  96. }
  97. #endif
  98. else if (*start == '[') {
  99. /* A "[section]" line */
  100. end = find_char_or_comment(start + 1, ']');
  101. if (*end == ']') {
  102. *end = '\0';
  103. strncpy0(section, start + 1, sizeof(section));
  104. *prev_name = '\0';
  105. }
  106. else if (!error) {
  107. /* No ']' found on section line */
  108. error = lineno;
  109. }
  110. }
  111. else if (*start && *start != ';') {
  112. /* Not a comment, must be a name[=:]value pair */
  113. end = find_char_or_comment(start, '=');
  114. if (*end != '=') {
  115. end = find_char_or_comment(start, ':');
  116. }
  117. if (*end == '=' || *end == ':') {
  118. *end = '\0';
  119. name = rstrip(start);
  120. value = lskip(end + 1);
  121. end = find_char_or_comment(value, '\0');
  122. if (*end == ';')
  123. *end = '\0';
  124. rstrip(value);
  125.  
  126. /* Valid name[=:]value pair found, call handler */
  127. strncpy0(prev_name, name, sizeof(prev_name));
  128. if (!handler(user, section, name, value) && !error)
  129. error = lineno;
  130. }
  131. else if (!error) {
  132. /* No '=' or ':' found on name[=:]value line */
  133. error = lineno;
  134. }
  135. }
  136.  
  137. #if INI_STOP_ON_FIRST_ERROR
  138. if (error)
  139. break;
  140. #endif
  141. }
  142.  
  143. #if !INI_USE_STACK
  144. free(line);
  145. #endif
  146.  
  147. return error;
  148. }
  149.  
  150. int ini_parse(const char* filename,
  151. int(*handler)(void*, const char*, const char*, const char*),
  152. void* user)
  153. {
  154. FILE* file;
  155. int error;
  156.  
  157. file = fopen(filename, "r");
  158. if (!file)
  159. return -1;
  160. error = ini_parse_file(file, handler, user);
  161. fclose(file);
  162. return error;
  163. }
  164.  
Datei:  Headerdateien/INIReader.h
  1. #ifndef __INIREADER_H__
  2. #define __INIREADER_H__
  3. #include <map>
  4. #include <string>
  5. class INIReader
  6. {
  7. public:
  8. INIReader(std::string filename);
  9. int ParseError();
  10. std::string GetString(std::string section, std::string name, std::string default_value);
  11. long GetInteger(std::string section, std::string name, long default_value);
  12. double GetDouble(std::string section, std::string name, double default_value);
  13. bool GetBoolean(std::string section, std::string name, bool default_value);
  14.  
  15. private:
  16. int _error;
  17. std::map<std::string, std::string> _values;
  18. static std::string MakeKey(std::string section, std::string name);
  19. static int ValueHandler(void* user, const char* section, const char* name, const char* value);
  20. };
  21. #endif
Datei:  Quelldateien/INIReader.cpp
  1. #include <algorithm>
  2. #include <cctype>
  3. #include <cstdlib>
  4. #include "ini.h"
  5. #include "INIReader.h"
  6.  
  7. using std::string;
  8.  
  9. INIReader::INIReader(string filename)
  10. {
  11. _error = ini_parse(filename.c_str(), ValueHandler, this);
  12. }
  13.  
  14. int INIReader::ParseError()
  15. {
  16. return _error;
  17. }
  18.  
  19. string INIReader::GetString(string section, string name, string default_value)
  20. {
  21. string key = MakeKey(section, name);
  22. return _values.count(key) ? _values[key] : default_value;
  23. }
  24.  
  25. long INIReader::GetInteger(string section, string name, long default_value)
  26. {
  27. string valstr = GetString(section, name, "");
  28. const char* value = valstr.c_str();
  29. char* end;
  30. long n = strtol(value, &end, 0);
  31. return end > value ? n : default_value;
  32. }
  33.  
  34. double INIReader::GetDouble(string section, string name, double default_value)
  35. {
  36. string valstr = GetString(section, name, "");
  37. const char* value = valstr.c_str();
  38. char* end;
  39. double n = strtod(value, &end);
  40. return end > value ? n : default_value;
  41. }
  42.  
  43. bool INIReader::GetBoolean(string section, string name, bool default_value)
  44. {
  45. string valstr = GetString(section, name, "");
  46. std::transform(valstr.begin(), valstr.end(), valstr.begin(), ::tolower);
  47. if (valstr == "true" || valstr == "yes" || valstr == "on" || valstr == "1")
  48. return true;
  49. else if (valstr == "false" || valstr == "no" || valstr == "off" || valstr == "0")
  50. return false;
  51. else
  52. return default_value;
  53. }
  54.  
  55. string INIReader::MakeKey(string section, string name)
  56. {
  57. string key = section + "." + name;
  58. std::transform(key.begin(), key.end(), key.begin(), ::tolower);
  59. return key;
  60. }
  61.  
  62. int INIReader::ValueHandler(void* user, const char* section, const char* name, const char* value)
  63. {
  64. INIReader* reader = (INIReader*)user;
  65. string key = MakeKey(section, name);
  66. if (reader->_values[key].size() > 0)
  67. reader->_values[key] += "\n";
  68. reader->_values[key] += value;
  69. return 1;
  70. }
  71.  
  72.  

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
  1. ; Konfigurationsdatei
  2. [protocol]
  3. version = 0xFF ; int sowie hex erlaubt
  4. # gespeicherte einstellungen
  5. [user]
  6. name = Johnny Wayne
  7. email = johnny@gmx.de
  8. active = true
  9. pi = 3.141592
Datei:  Quelldateien/main.cpp
  1. #include <iostream> // std::cout, std::endl, std::cin
  2. #include <stdlib.h> // EXIT_SUCCESS, EXIT_FAILURE
  3. #include "INIReader.h"
  4.  
  5. int main(void)
  6. {
  7. std::cout << "ini files einlesen\n" << std::endl;
  8. INIReader ini("config.ini");
  9. if (ini.ParseError() < 0)
  10. {
  11. std::cerr << "Can't load 'config.ini'\n";
  12. return EXIT_FAILURE;
  13. }
  14. std::cout << "version=" << ini.GetInteger("protocol", "version", -1) << std::endl;
  15. std::cout << "name=" << ini.GetString("user", "name", "UNKNOWN") << std::endl;
  16. std::cout << "email=" << ini.GetString("user", "email", "UNKNOWN") << std::endl;
  17. std::cout << "pi=" << ini.GetDouble("user", "pi", -1) << std::endl;
  18. std::cout << "active=" << ini.GetBoolean("user", "active", true) << "\n\n";
  19.  
  20. std::cin.get();
  21. return EXIT_SUCCESS;
  22. }

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!

Kommentare zu diesem Beitrag

Sie müssen angemeldet sein, um eine Nachricht zu erstellen. Anmelden »