A small and portable INI file library with read/write support

Overview

minIni

minIni is a portable and configurable library for reading and writing ".INI" files. At just below 900 lines of commented source code, minIni truly is a "mini" INI file parser, especially considering its features.

The library does not require the file I/O functions from the standard C/C++ library, but instead lets you configure the file I/O interface to use via macros. minIni uses limited stack space and does not use dynamic memory (malloc and friends) at all.

Some minor variations on standard INI files are supported too, notably minIni supports INI files that lack sections.

Acknowledgement

minIni is derived from an earlier INI file parser (which I wrote) for desktop systems.

In turn, that earlier parser was a re-write of the code from the article "Multiplatform .INI Files" by Joseph J. Graf in the March 1994 issue of Dr. Dobb's Journal. In other words, minIni has its roots in the work of Joseph Graf (even though the code has been almost completely re-written).

Features

minIni is a programmer's library to read and write "INI" files in embedded systems. minIni takes little resources, can be configured for various kinds of file I/O libraries and provides functionality for reading, writing and deleting keys from an INI file.

Although the main feature of minIni is that it is small and minimal, it has a few other features:

  • minIni supports reading keys that are outside a section, and it thereby supports configuration files that do not use sections (but that are otherwise compatible with INI files).
  • You may use a colon to separate key and value; the colon is equivalent to the equal sign. That is, the strings "Name: Value" and "Name=Value" have the same meaning.
  • The hash character ("#") is an alternative for the semicolon to start a comment. Trailing comments (i.e. behind a key/value pair on a line) are allowed.
  • Leading and trailing white space around key names and values is ignored.
  • When writing a value that contains a comment character (";" or "#"), that value will automatically be put between double quotes; when reading the value, these quotes are removed. When a double-quote itself appears in the setting, these characters are escaped.
  • Section and key enumeration are supported.
  • You can optionally set the line termination (for text files) that minIni will use. (This is a compile-time setting, not a run-time setting.)
  • Since writing speed is much lower than reading speed in Flash memory (SD/MMC cards, USB memory sticks), minIni minimizes "file writes" at the expense of double "file reads".
  • The memory footprint is deterministic. There is no dynamic memory allocation.

INI file reading paradigms

There are two approaches to reading settings from an INI file. One way is to call a function, such as GetProfileString() for every section and key that you need. This is especially convenient if there is a large INI file, but you only need a few settings from that file at any time —especially if the INI file can also change while your program runs. This is the approach that the Microsoft Windows API uses.

The above procedure is quite inefficient, however, when you need to retrieve quite a few settings in a row from the INI file —especially if the INI file is not cached in memory (which it isn't, in minIni). A different approach to getting settings from an INI file is to call a "parsing" function and let that function call the application back with the section and key names plus the associated data. XML parsing libraries often use this approach; see for example the Expat library.

minIni supports both approaches. For reading a single setting, use functions like ini_gets(). For the callback approach, implement a callback and call ini_browse(). See the minIni manual for details.

INI file syntax

INI files are best known from Microsoft Windows, but they are also used with applications that run on other platforms (although their file extension is sometimes ".cfg" instead of ".ini").

INI files have a simple syntax with name/value pairs in a plain text file. The name must be unique (per section) and the value must fit on a single line. INI files are commonly separated into sections —in minIni, this is optional. A section is a name between square brackets, like "[Network]" in the example below.

[Network]
hostname=My Computer
address=dhcp
dns = 192.168.1.1

In the API and in this documentation, the "name" for a setting is denoted as the key for the setting. The key and the value are separated by an equal sign ("="). minIni supports the colon (":") as an alternative to the equal sign for the key/value delimiter.

Leading a trailing spaces around values or key names are removed. If you need to include leading and/or trailing spaces in a value, put the value between double quotes. The ini_gets() function (from the minIni library, see the minIni manual) strips off the double quotes from the returned value. Function ini_puts() adds double quotes if the value to write contains trailing white space (or special characters).

minIni ignores spaces around the "=" or ":" delimiters, but it does not ignore spaces between the brackets in a section name. In other words, it is best not to put spaces behind the opening bracket "[" or before the closing bracket "]" of a section name.

Comments in the INI must start with a semicolon (";") or a hash character ("#"), and run to the end of the line. A comment can be a line of its own, or it may follow a key/value pair (the "#" character and trailing comments are extensions of minIni).

For more details on the format, please see http://en.wikipedia.org/wiki/INI_file.

Adapting minIni to a file system

The minIni library must be configured for a platform with the help of a so- called "glue file". This glue file contains macros (and possibly functions) that map file reading and writing functions used by the minIni library to those provided by the operating system. The glue file must be called "minGlue.h".

To get you started, the minIni distribution comes with the following example glue files:

The minIni library does not rely on the availability of a standard C library, because embedded operating systems may have limited support for file I/O. Even on full operating systems, separating the file I/O from the INI format parsing carries advantages, because it allows you to cache the INI file and thereby enhance performance.

The glue file must specify the type that identifies a file, whether it is a handle or a pointer. For the standard C/C++ file I/O library, this would be:

#define INI_FILETYPE        FILE*

If you are not using the standard C/C++ file I/O library, chances are that you need a different handle or "structure" to identify the storage than the ubiquitous "FILE*" type. For example, the glue file for the FatFs library uses the following declaration:

#define INI_FILETYPE        FIL

The minIni functions declare variables of this INI_FILETYPE type and pass these variables to sub-functions (including the glue interface functions) by reference.

For "write support", another type that must be defined is for variables that hold the "current position" in a file. For the standard C/C++ I/O library, this is "fpos_t".

Another item that needs to be configured is the buffer size. The functions in the minIni library allocate this buffer on the stack, so the buffer size is directly related to the stack usage. In addition, the buffer size determines the maximum line length that is supported in the INI file and the maximum path name length for the temporary file. For example, minGlue.h could contain the definition:

#define INI_BUFFERSIZE      512

The above macro limits the line length of the INI files supported by minIni to 512 characters.

The temporary file is only used when writing to INI files. The minIni routines copy/change the INI file to a temporary file and then rename that temporary file to the original file. This approach uses the least amount of memory. The path name of the temporary file is the same as the input file, but with the last character set to a tilde ("~").

Below is an example of a glue file (this is the one that maps to the C/C++ "stdio" library).

#include <stdio.h>

#define INI_FILETYPE                  FILE*
#define ini_openread(filename,file)   ((*(file) = fopen((filename),"r")) != NULL)
#define ini_openwrite(filename,file)  ((*(file) = fopen((filename),"w")) != NULL)
#define ini_close(file)               (fclose(*(file)) == 0)
#define ini_read(buffer,size,file)    (fgets((buffer),(size),*(file)) != NULL)
#define ini_write(buffer,file)        (fputs((buffer),*(file)) >= 0)
#define ini_rename(source,dest)       (rename((source), (dest)) == 0)
#define ini_remove(filename)          (remove(filename) == 0)

#define INI_FILEPOS                   fpos_t
#define ini_tell(file,pos)            (fgetpos(*(file), (pos)) == 0)
#define ini_seek(file,pos)            (fsetpos(*(file), (pos)) == 0)

As you can see, a glue file is mostly a set of macros that wraps one function definition around another.

The glue file may contain more settings, for support of rational numbers, to explicitly set the line termination character(s), or to disable write support (for example). See the manual that comes with the archive for the details.

Comments
  • Does not compile for embedded platform

    Does not compile for embedded platform

    I am using minIni for embedded system (ESP32). The compiler failed at _tcsnicmp --> strnicmp. I see that this is defined when __linux is defined (_tcsnicmp --> strncasecmp). My compiler is gcc which is similar to linux. Could you add switch for gcc ?

    opened by alsaleem00 2
  • minGlue.h missing include guard

    minGlue.h missing include guard

    Hello guys, I've imported your repo as a submodule in my project and I've rewritten the minGlue.h. Can you please add include guard around the minGlue.h? Thanks

    wontfix 
    opened by KestrelLuca 1
  • Leaking file descriptors

    Leaking file descriptors

    https://github.com/compuphase/minIni/blob/51d636f9c60f8d013860965565b447ef14dc2286/dev/minGlue-Linux.h#L23-L25 the file descriptor returned by the first fopen ends up being leaked

    wontfix 
    opened by Jan200101 1
  • Make a release

    Make a release

    We are using minIni in one of our TensorFlow extensions. Instead of copying minIni code directly into our code repo, it would be much better to have a release archive we can use as an http_archive, like the ones here: https://github.com/tensorflow/io/blob/master/WORKSPACE#L184

    opened by zou000 1
  • wrong assert in save_strncpy

    wrong assert in save_strncpy

    This code at beginning of save_strncpy has an error: assert(dest <= source || dest >= source + maxlen);

    Because maxlen is a target attribute I expect somewhat like in second part: dest > source + strlen(source) For example, ini_gets fails if Buffer placed in memory immediatelly after very short DefValue.

    Also, I expect that dest should be filled by '\', when both option == QUOTE_ENQUOTE and dest == source.

    opened by skycetus 1
  • remove

    remove "const" from UserData for ini_browse

    Just a suggestion for this nice library: user data should not be forced as const.

    Removing const on UserData in these lines is enough for this: https://github.com/compuphase/minIni/blob/master/dev/minIni.h#L59 and line 60 https://github.com/compuphase/minIni/blob/master/dev/minIni.c#L461

    opened by iweindesmedt 1
  • Minor: Documentation for ini_getbool mentions nonexisting parameters

    Minor: Documentation for ini_getbool mentions nonexisting parameters

    Xcodes analyser notes that the doxygen code for ini_getbool mentions the parameters Buffer and BufferSize, which are not present in the function definition, which appears to be true:

    /** ini_getbool()
    [...]
     * \param Buffer      a pointer to the buffer to copy into
     * \param BufferSize  the maximum number of characters to copy
    [...]
    int ini_getbool(const TCHAR *Section, const TCHAR *Key, int DefValue, const TCHAR *Filename)
    

    I'm not really sure how to note that but I created a pull request here: #4

    opened by tinus-github 1
  • Code style in cache_flush() function

    Code style in cache_flush() function

    First of all thanks for the library. One minor correction: function static int cache_flush(TCHAR *buffer, int *size, INI_FILETYPE *rfp, INI_FILETYPE *wfp, INI_FILEPOS *mark); uses constant INI_BUFFERSIZE as a size of its argument buffer. This is the case while library is unmodified but it would be safer to pass size of a buffer as an argument.

    opened by mir-math 0
  • Cannot cmpare a character correctly

    Cannot cmpare a character correctly

    image As shown in the above figure, when I run the demo, I locate that it can't work normally here. I use visual studio2015. I don't know why this happens. Thank you!

    opened by Telly-S 1
  • Handling multiple file system types

    Handling multiple file system types

    There are a lot of situations where we need to store data with a tiny file system (like SPIFFS) into an internal flash memory mounted directly in a board. There are another situations where with need to read/store ini configuration from an external SD Card.

    In that case we need to be able to manage a multiple file system types in the same project.

    Could be nice to add the possibility to manage multiple file system types in the same project.

    What do you think about?

    opened by GiulioDallaVecchia 0
  • hope can add

    hope can add "delete a line of comments ‘#’ "

    [Hotkey]
    # 切换激活/非激活输入法
    TriggerKey=CTRL_SPACE
    # 只在用额外切换键取消激活后才使用它进行切换
    # 可选值:
    # True False
    #UseExtraTriggerKeyOnlyWhenUseItToInactivate=True
    # 额外的激活输入法快捷键
    

    some times i want remove "#" from "#UseExtraTriggerKeyOnlyWhenUseItToInactivate=True".

    make "UseExtraTriggerKeyOnlyWhenUseItToInactivate=True" be usefull.

    opened by xingwozhonghua 0
  • Consider preserving comments when re-writing values?

    Consider preserving comments when re-writing values?

    I've been searching quite a bit for an easy to use C config file library that supports preserving comments.

    If I have the following in my INI file.

    [section:foo]
    alpha=True ; comment preserved
    beta=True  ; until the value changes
    

    And then use minIni to change the value of beta:

      ini_puts("section:foo", "beta", "False", inifile2);
    

    The comment on beta will be lost...

    [section:foo]
    alpha=True ; comment preserved
    beta=False
    

    Not every config value change will invalidate the meaning of the associated comment, and since minIni doesn't write comments, only the user should be writing comments... Would be very frustrating for the end user to loose some comments they thought were important when we rewrite config changes.

    As a workaround, one idea that comes to mind is putting a prefix or a suffix or both on the subset of key values that your program will be re-writing, so that these values jump out to the user as odd in the config file and are less surprised when comments there disappear. The downside of this approach would be as your software evolves and a value goes from user only to program re-written with the same name, so not an ideal workaround.

    Something like:

    [section:foo]
    normal_key = value ; description of normal key
    $app_configured = other value ; maybe less surprising if this comment gets erased?
    
    opened by erwin 0
Releases(1.3)
ini file parser

Iniparser 4 I - Overview This modules offers parsing of ini files from the C level. See a complete documentation in HTML format, from this directory o

Nicolas D 845 Jan 1, 2023
PhysicsFS; a portable, flexible file i/o abstraction.

PhysicsFS; a portable, flexible file i/o abstraction.

Ryan C. Gordon 300 Jan 7, 2023
Small configuration file parser library for C.

libConfuse Introduction Documentation Examples Build & Install Origin & References Introduction libConfuse is a configuration file parser library writ

null 419 Dec 14, 2022
Libelf is a simple library to read ELF files

libelf Libelf is a simple library which provides functions to read ELF files. Headers #include <stdint.h> #include <elf.h> Structures typedef struct

David du Colombier 44 Aug 7, 2022
Find patterns of vulnerabilities on Windows in order to find 0-day and write exploits of 1-days. We use Microsoft security updates in order to find the patterns.

Back 2 the Future Find patterns of vulnerabilities on Windows in order to find 0-day and write exploits of 1-days. We use Microsoft security updates i

SafeBreach Labs 118 Dec 30, 2022
Read Non-Rectangular Text Data

meltr The goal of ‘meltr’ is to provide a fast and friendly way to read non-rectangular data (like ragged forms of ‘csv’, ‘tsv’, and ‘fwf’). Standard

R infrastructure 29 Dec 26, 2022
LoL-Reader is a tool to read game-state.

LoL-Reader LoL-Reader is a tool to read real-time League of Legends statistics from memory. Installation - Compile g++ *.cpp -L. -lPsapi -w -o progra

Kaan Caglan 2 Dec 28, 2021
libcurses and dependencies taken from netbsd and brought into a portable shape (at least to musl or glibc)

netbsd-libcurses portable edition this is a port of netbsd's curses library for usage on Linux systems (tested and developed on sabotage linux, based

null 124 Nov 7, 2022
convert elf file to single c/c++ header file

elf-to-c-header Split ELF to single C/C++ header file

Musa Ünal 2 Nov 4, 2021
Internet Key Exchange version 2 (IKEv2) daemon - portable version of OpenBSD iked

Portable OpenIKED This is a port of OpenBSD's OpenIKED to different Unix-like operating systems, including Linux, macOS and FreeBSD.

OpenIKED 27 Dec 4, 2022
Small header-only C++ library that helps to initialize Vulkan instance and device object

Vulkan Extensions & Features Help, or VkExtensionsFeaturesHelp, is a small, header-only, C++ library for developers who use Vulkan API.

Adam Sawicki 11 Oct 12, 2022
libparser is a small C library that parses input based on a precompiled context-free grammar.

libparser is a small C library that parses input based on a precompiled context-free grammar.

Mattias Andrée 9 Jul 19, 2022
Small Header only library to parse argv for flags

Small Header only library to parse argv for flags

Ben Wernicke 3 Nov 9, 2022
GNU project's implementation of the standard C library(with Xuantie RISC-V CPU support).

GNU project's implementation of the standard C library(with Xuantie RISC-V CPU support).

T-Head Semiconductor Co., Ltd. 5 Mar 17, 2022
This library support run-time type casting faster than dynamic_cast ( similar to unreal engine's CastTo )

Fast Runtime Type Casting This library give you C++ Fast Runtime Type Casting faster than dynamic_cast ( similar to Unreal Engine's CastTo, IsChildOf

SungJinKang 7 Jun 11, 2022
A linux library to get the file path of the currently running shared library. Emulates use of Win32 GetModuleHandleEx/GetModuleFilename.

whereami A linux library to get the file path of the currently running shared library. Emulates use of Win32 GetModuleHandleEx/GetModuleFilename. usag

Blackle Morisanchetto 3 Sep 24, 2022
A small self-contained alternative to readline and libedit

Linenoise A minimal, zero-config, BSD licensed, readline replacement used in Redis, MongoDB, and Android. Single and multi line editing mode with the

Salvatore Sanfilippo 3.1k Dec 30, 2022
A small proxy DLL which enables dev. console in Mass Effect 1, 2 and 3 (Legendary Edition).

LEBinkProxy A small proxy DLL which enables dev. console in Mass Effect 1, 2 and 3 (Legendary Edition). Usage In your game binary directory (Game\ME?\

null 10 Jan 6, 2022
A shebang-friendly script for "interpreting" single C99, C11, and C++ files, including rcfile support.

c99sh Basic Idea Control Files Shebang Tricks C++ C11 Credits Basic Idea A shebang-friendly script for "interpreting" single C99, C11, and C++ files,

Rhys Ulerich 100 Dec 3, 2022