Giter VIP home page Giter VIP logo

mini's Introduction

mINI

v0.9.15

Info

This is a tiny, header only C++ library for manipulating INI files.

It conforms to the following format:

  • section and key names are case insensitive
  • whitespace around sections, keys and values is ignored
  • empty section and key names are allowed
  • keys that do not belong to a section are ignored
  • comments are lines where the first non-whitespace character is a semicolon (;)
  • trailing comments are allowed on section lines, but not key/value lines
  • every entry exists on a single line and multiline is not supported
; comment
[section]
key = value

Files are read on demand in one go, after which the data is kept in memory and is ready to be manipulated. Files are closed after read or write operations. This utility supports lazy writing, which only writes changes and updates and preserves custom formatting and comments. A lazy write invoked by a write() call will read the output file, find which changes have been made, and update the file accordingly. If you only need to generate files, use generate() instead.

Section and key order is preserved on read and write operations. Iterating through data will take the same order as the original file or the order in which keys were added to the structure.

This library operates with the std::string type to hold values and relies on your host environment for encoding. It should play nicely with UTF-8 but your mileage may vary.

Installation

This is a header-only library. To install it, just copy everything in /src/ into your own project's source code folder, or use a custom location and just make sure your compiler sees the additional include directory. Then include the file somewhere in your code:

#include "mini/ini.h"

You're good to go!

Basic examples

Reading / writing

Start with an INI file named myfile.ini:

; amounts of fruits
[fruits]
apples=20
oranges=30

Our code:

// first, create a file instance
mINI::INIFile file("myfile.ini");

// next, create a structure that will hold data
mINI::INIStructure ini;

// now we can read the file
file.read(ini);

// read a value
std::string& amountOfApples = ini["fruits"]["apples"];

// update a value
ini["fruits"]["oranges"] = "50";

// add a new entry
ini["fruits"]["bananas"] = "100";

// write updates to file
file.write(ini);

After running the code, our INI file now looks like this:

; amounts of fruits
[fruits]
apples=20
oranges=50
bananas=100

Generating a file

// create a file instance
mINI::INIFile file("myfile.ini");

// create a data structure
mINI::INIStructure ini;

// populate the structure
ini["things"]["chairs"] = "20";
ini["things"]["balloons"] = "100";

// generate an INI file (overwrites any previous file)
file.generate(ini);

Manipulating files

The INIFile class holds the filename and exposes functions for reading, writing and generating INI files. It does not keep the file open but merely provides an abstraction you can use to access physical files.

To create a file instance:

mINI::INIFile file("myfile.ini");

You will also need a structure you can operate on:

mINI::INIStructure ini;

To read from a file:

bool readSuccess = file.read(ini);

To write back to a file while preserving comments and custom formatting:

bool writeSuccess = file.write(ini);

You can set the second parameter to write() to true if you want the file to be written with pretty-print. Pretty-print adds spaces between key-value pairs and blank lines between sections in the output file:

bool writeSuccess = file.write(ini, true);

A write() call will attempt to preserve any custom formatting the original INI file uses and will only use pretty-print for creation of new keys and sections.

To generate a file:

file.generate(ini);

Note that generate() will overwrite any custom formatting and comments from the original file!

You can use pretty-print with generate() as well:

file.generate(ini, true);

Example output for a generated INI file without pretty-print:

[section1]
key1=value1
key2=value2
[section2]
key1=value1

Example output for a generated INI file with pretty-print:

[section1]
key1 = value1
key2 = value2

[section2]
key1 = value1

Manipulating data

Reading data

There are two ways to read data from the INI structure. You can either use the [] operator or the get() function:

// read value - if key or section don't exist, they will be created
// returns reference to real value
std::string& value = ini["section"]["key"];

// read value safely - if key or section don't exist they will NOT be created
// returns a copy
std::string value = ini.get("section").get("key");

The difference between [] and get() operations is that [] returns a reference to real data (that you may modify) and creates a new item automatically if one does not already exist, whereas get() returns a copy of the data and doesn't create new items in the structure. Use has() before doing any operations with [] if you wish to avoid altering the structure.

You may combine usage of [] and get().

Section and key names are case insensitive and are stripped of leading and trailing whitespace. ini["section"] is the same as ini["SECTION"] is the same as ini[" sEcTiOn "] and so on, and same for keys. Generated files always use lower case for section and key names. Writing to an existing file will preserve letter cases of the original file whenever those keys or sections already exists.

Updating data

To set or update a value:

ini["section"]["key"] = "value";

Note that when writing to a file, values will be stripped of leading and trailing whitespace . For example, the following value will be converted to just "c" when reading back from a file: ini["a"]["b"] = " c ";

You can set multiple values at once by using set():

ini["section"].set({
	{"key1", "value1"},
	{"key2", "value2"}
});

To create an empty section, simply do:

ini["section"];

Similarly, to create an empty key:

ini["section"]["key"];

To remove a single key from a section:

bool removeSuccess = ini["section"].remove("key");

To remove a section:

bool removeSuccess = ini.remove("section");

To remove all keys from a section:

ini["section"].clear();

To remove all data in structure:

ini.clear();

Other functions

To check if a section is present:

bool hasSection = ini.has("section");

To check if a key within a section is present:

bool hasKey = ini["section"].has("key");

To get the number of keys in a section:

size_t n_keys = ini["section"].size();

To get the number of sections in the structure:

size_t n_sections = ini.size();

Nitty-gritty

Keep in mind that [] will always create a new item if the item does not already exist! You can use has() to check if an item exists before performing further operations. Remember that get() will return a copy of data, so you should not be doing removes or updates to data with it!

Usage of the [] operator shouldn't be a problem in most real-world cases where you're doing lookups on known keys and you may not care if empty keys or sections get created. However - if you have a situation where you do not want new items to be added to the structure, either use get() to retreive items, or if you don't want to be working with copies of data, use has() before using the [] operator if you want to be on the safe side.

Short example that demonstrates safe manipulation of data:

if (ini.has("section"))
{
	// we have section, we can access it safely without creating a new one
	auto& collection = ini["section"];
	if (collection.has("key"))
	{
		// we have key, we can access it safely without creating a new one
		auto& value = collection["key"];
	}
}

Iteration

You can traverse the structure in order of insertion. The following example loops through the structure and displays results in a familiar format:

for (auto const& it : ini)
{
	auto const& section = it.first;
	auto const& collection = it.second;
	std::cout << "[" << section << "]" << std::endl;
	for (auto const& it2 : collection)
	{
		auto const& key = it2.first;
		auto const& value = it2.second;
		std::cout << key << "=" << value << std::endl;
	}
}

it.first is always std::string type.

it.second is an object which is either a mINI::INIMap type on the first level or std::string type on the second level.

The API only exposes a const_iterator, so you can't use iterators to manipulate data directly. You can however access the structure as normal while iterating:

// change all values in the structure to "banana"
for (auto const& it : ini)
{
	auto const& section = it.first;
	auto const& collection = it.second;
	for (auto const& it2 : collection)
	{
		auto const& key = it2.first;
		ini[section][key] = "banana"; // O(1) because hashmaps
	}
}

Case sensitivity

If you wish to make the library not ignore letter case, add the directive #define MINI_CASE_SENSITIVE before including the library:

#define MINI_CASE_SENSITIVE
#include "mini/ini.h"

This will affect reading and writing from files and access to the structure.

Thanks

  • lest - testing framework

License

Copyright © 2018 Danijel Durakovic

Licensed under the terms of the MIT license

mini's People

Contributors

jmgr avatar luizfernandonb avatar mabelyt avatar meisenzahl avatar metayeti avatar snazarkin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mini's Issues

Output is being prefixed with gabage

Hello,

I am trying to write a simple program and cannot get past the first part of reading an ini files. I saw you library and downloaded and installed it. It is reading my ini file but the output is being prefix with some sort of gabage. For now I only have the ini portion of the code so here it is:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include
#include
#include "mini/ini.h"

using namespace std;

int main()
{
mINI::INIFile file("clean-folders.ini");
mINI::INIStructure ini;
file.read(ini);

std::string dFolder = ini.get("folder").get("location");
std::string delay = ini.get("purge-minutes").get("min");

printf("%s" "%s" "%s", dFolder, delay, "\n");

return 0;

}

no support comment to the right value

  • no support comment to the right value

I added this.

if (equalsAt != std::string::npos)
{
auto key = line.substr(0, equalsAt);
INIStringUtil::trim(key);
INIStringUtil::replace(key, "\=", "=");
auto value = line.substr(equalsAt + 1);
auto commentAt = value.find_first_of(';');
if (commentAt != std::string::npos)
value = value.erase(commentAt, value.length());
INIStringUtil::trim(value);
parseData.first = key;
parseData.second = value;
return PDataType::PDATA_KEYVALUE;
}

Support for std::wstring

Hi, I write ini files in arabic paths which makes the app crash when passing a wide char* or a wstring path
Like: C:/somefoler/مجلد/settings.ini
Is there a feature for wstring filenames and what not?

Warnings on Windows with VS2022 MSVC /W4

mINI @ b5f0dc2

mini/ini.h(352,32): warning C4310: cast truncates constant value
mini/ini.h(352,59): warning C4310: cast truncates constant value
mini/ini.h(352,86): warning C4310: cast truncates constant value
mini/ini.h(711,38): warning C4310: cast truncates constant value
mini/ini.h(711,50): warning C4310: cast truncates constant value
mini/ini.h(711,62): warning C4310: cast truncates constant value

trailing comments on all lines

Would it be possible to add support for trailing comments on key/value lines? It would be nice to leave a comment here and there for the end users (or myself) of my program. Maybe a relatively crude method would suffice? Store everything after the value as a comment, no matter how much whitespace, etc.?

key = value ; This is the background color

While writing, simply append the stored string back to the value.

Pretty please.

const std::string

There are several places in code you're using const std::string to define whitespace and end-of-line strings. There are a couple of issues with this.

First, these aren't inline, meaning that an instance is created for every translation unit.

Second, because you're using std::string, this performs an unnecessary allocation in debug mode (it disappears in release due to SSO). This is causing me problems with my leak detection, since the deallocation order isn't guaranteed, and is occurring after my leak check exit point.

It would be best to simply replace these several instances with inline const char* This will avoid any allocations, and works exactly like before.

inline const char* whitespaceDelimiters = " \t\n\r\f\v";
...
#ifdef _WIN32
    inline const char* endl = "\r\n";
#else
    inline const char* endl = "\n";
#endif

Location of the file in linux

Hi,
what should be the location of the .ini file in linux?

I used to have the ini file along with my application in /usr/bin, but if I launch the application within a different directory it does not read the ini file.

Example (myapplication is the name of the application, it has a myapplication.ini file):

root@localhost:~# myapplication  // The application does not find the ini file
root@localhost:~#  cd /usr/bin
root@localhost:/usr/bin# myapplication // The application does find the ini file

Is there a way to tell the path where to look for the ini file?
Thanks!

error while using std::stoi with string from mINI.

Hi,
I'm trying to use the int from the ini file but I can't because when I run it I get the message:
terminate called after throwing an instance of 'std::invalid_argument'
what(): stands
Does anyone know how to fix this?
Thanks!

mIni doesn't parse properly strings

Hi !
I realised a problem in mIni as it doesn't parse strings properly, the string should be parsed as A MineServer ! but is instead parsed as A.

Config :

[network]
port = 25565

[display]
motd = A MineServer !

[other]
max-players = 100

Using logging here is what I get :

[DEBUG] 10:34:32 - Parsed port as 25565
[DEBUG] 10:34:32 - Parsed motd as A
[DEBUG] 10:34:32 - Parsed max-players as 100
[INFO]  10:34:32 - Motd : A

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.