Lightweight, header-based configuration library for C++17, providing INI-style file parsing with type-safe value access and section/key management.
This library provides:
- Type-safe configuration values (
bool,int32_t,double,std::string) - INI file format with section support
- Automatic type parsing and serialization
- Comment preservation (full round-trip support)
- Quoted string values β
"..."and'...'protect#and;from being parsed as comments - Section and key iteration via
GetSectionList/GetEntryList - Simple bind system for easy variable management
config.hpp β Main library header (ConfigEntry, Config)
config.cpp β Implementation
config_c.h β C-compatible API header
config_c.cpp β C-compatible API implementation
- C++17 compiler
- Standard Library (
string,variant,unordered_map,vector,fstream,cstdint)
No external dependencies.
#include "config.hpp"
Config cfg("settings"); // opens settings.ini
cfg.Load();
// Bind or create entries
ConfigEntry& volume = cfg.Bind("volume", 0.75, "Audio");
ConfigEntry& fullscreen = cfg.Bind("fullscreen", true);
// Read values
double vol = volume.Get<double>(); // 0.75
bool fs = fullscreen.Get<bool>(); // true
// Modify values
volume.Set(0.8);
fullscreen.Set(false);
// Save back to file
cfg.Save();Config cfg("game");
cfg.Load();
ConfigEntry& username = cfg.Bind("name", std::string("player"), "Account");
ConfigEntry& score = cfg.Bind("highscore", int32_t{0}, "Stats");
if (cfg.HasSection("Account")) {
// section exists
}
if (cfg.HasKey("name", "Account")) {
std::string name = cfg.Bind("name", std::string{}, "Account").Get<std::string>();
}Config cfg("settings");
cfg.Load();
for (const std::string& section : cfg.GetSectionList()) {
std::cout << "[" << section << "]\n";
for (const ConfigEntry* entry : cfg.GetEntryList(section)) {
std::cout << " " << entry->GetKey() << " = ";
if (entry->IsInt()) std::cout << entry->Get<int32_t>();
if (entry->IsDouble()) std::cout << entry->Get<double>();
if (entry->IsBool()) std::cout << entry->Get<bool>();
if (entry->IsString()) std::cout << entry->Get<std::string>();
std::cout << "\n";
}
}# Global section (no brackets)
fullscreen = true
language = english
[Audio]
volume = 0.8 ; inline comment with semicolon
muted = false
[Graphics]
width = 1920 # inline comment with hash
vsync = true
[Paths]
save_dir = "C:\Users\save ; folder" ; semicolon inside quotes is preserved
label = "hello #world" ; hash inside quotes is preservedConfigEntry& entry = cfg.Bind("answer", int32_t{42});
int32_t value = entry.Get<int32_t>(); // OK: 42
double f = entry.Get<double>(); // Returns fallback 0.0
bool b = entry.Get<bool>(); // Returns fallback false
if (entry.IsInt()) {
int32_t x = entry.Get<int32_t>();
}// Original file:
// # This is a comment
// fullscreen = true
//
// [Audio] # section comment
// volume = 0.8 # inline comment
cfg.Load();
cfg.Bind("volume", 0.0, "Audio").Set(0.9);
cfg.Save();
// Saved file preserves all comments:
// # This is a comment
// fullscreen = true
//
// [Audio] # section comment
// volume = 0.9 # inline comment| Method | Description |
|---|---|
Set<T>(const T& value) |
Sets the entry value. T must be bool, int32_t, double, or std::string |
Get<T>(const T& fallback = {}) |
Returns value if type matches, otherwise returns fallback |
GetKey() |
Returns the entry's key name |
GetSection() |
Returns the entry's section name (empty string = global) |
GetInlineComment() |
Returns the inline comment string, if any |
GetPreComments() |
Returns comment lines that appear before this entry |
IsBool() |
Returns true if the stored type is bool |
IsInt() |
Returns true if the stored type is int32_t |
IsDouble() |
Returns true if the stored type is double |
IsString() |
Returns true if the stored type is std::string |
| Method | Description |
|---|---|
Config(const std::string& configName) |
Constructor. Appends .ini to the provided name |
Load() |
Loads and parses the INI file |
Save() |
Saves current values preserving all comments |
Bind(key, defaultValue, section = "") |
Returns existing entry or creates a new one with defaultValue |
HasSection(section) |
Returns true if the section exists |
HasKey(key, section = "") |
Returns true if the key exists in the given section |
CanInteract() |
Returns true if the file is accessible for read/write |
GetSectionList() |
Returns sorted list of all section names (empty string = global) |
GetEntryList(section = "") |
Returns sorted list of pointers to all entries in the given section |
- Values are stored as
std::variant<bool, int32_t, double, std::string> intliterals bind asint32_t; floating-point literals bind asdouble- Inline comments are supported with both
#and; - String values containing
#or;must be wrapped in quotes ("..."or'...') in the INI file;Save()adds quotes automatically when needed doublevalues are always serialized with a decimal point (e.g.90.0) to survive reload asdoubleinstead ofint32_t- Boolean values:
true/false(case-sensitive) - Empty lines and all comment styles are preserved on round-trip
| v1.x | v2.0 |
|---|---|
int |
int32_t |
float |
double |
IsFloat() |
IsDouble() |
Config_BindFloat |
Config_BindDouble |
ConfigEntry_GetFloat |
ConfigEntry_GetDouble |
ConfigEntry_SetFloat |
ConfigEntry_SetDouble |
Only # as comment marker |
# and ; both supported |
| No iteration API | GetSectionList / GetEntryList |
π License
π€ Credits
- DeviceBlack β full implementation, design, and documentation