Simple .INI file parser in C, good for embedded systems

Overview

inih (INI Not Invented Here)

TravisCI Build

inih (INI Not Invented Here) is a simple .INI file parser written in C. It's only a couple of pages of code, and it was designed to be small and simple, so it's good for embedded systems. It's also more or less compatible with Python's ConfigParser style of .INI files, including RFC 822-style multi-line syntax and name: value entries.

To use it, just give ini_parse() an INI file, and it will call a callback for every name=value pair parsed, giving you strings for the section, name, and value. It's done this way ("SAX style") because it works well on low-memory embedded systems, but also because it makes for a KISS implementation.

You can also call ini_parse_file() to parse directly from a FILE* object, ini_parse_string() to parse data from a string, or ini_parse_stream() to parse using a custom fgets-style reader function for custom I/O.

Download a release, browse the source, or read about how to use inih in a DRY style with X-Macros.

Compile-time options

You can control various aspects of inih using preprocessor defines:

Syntax options

  • Multi-line entries: By default, inih supports multi-line entries in the style of Python's ConfigParser. To disable, add -DINI_ALLOW_MULTILINE=0.
  • UTF-8 BOM: By default, inih allows a UTF-8 BOM sequence (0xEF 0xBB 0xBF) at the start of INI files. To disable, add -DINI_ALLOW_BOM=0.
  • Inline comments: By default, inih allows inline comments with the ; character. To disable, add -DINI_ALLOW_INLINE_COMMENTS=0. You can also specify which character(s) start an inline comment using INI_INLINE_COMMENT_PREFIXES.
  • Start-of-line comments: By default, inih allows both ; and # to start a comment at the beginning of a line. You can override this by changing INI_START_COMMENT_PREFIXES.
  • Allow no value: By default, inih treats a name with no value (no = or : on the line) as an error. To allow names with no values, add -DINI_ALLOW_NO_VALUE=1, and inih will call your handler function with value set to NULL.

Parsing options

  • Stop on first error: By default, inih keeps parsing the rest of the file after an error. To stop parsing on the first error, add -DINI_STOP_ON_FIRST_ERROR=1.
  • Report line numbers: By default, the ini_handler callback doesn't receive the line number as a parameter. If you need that, add -DINI_HANDLER_LINENO=1.
  • Call handler on new section: By default, inih only calls the handler on each name=value pair. To detect new sections (e.g., the INI file has multiple sections with the same name), add -DINI_CALL_HANDLER_ON_NEW_SECTION=1. Your handler function will then be called each time a new section is encountered, with section set to the new section name but name and value set to NULL.

Memory options

  • Stack vs heap: By default, inih creates a fixed-sized line buffer on the stack. To allocate on the heap using malloc instead, specify -DINI_USE_STACK=0.
  • Maximum line length: The default maximum line length (for stack or heap) is 200 bytes. To override this, add something like -DINI_MAX_LINE=1000. Note that INI_MAX_LINE must be 3 more than the longest line (due to \r, \n, and the NUL).
  • Initial malloc size: INI_INITIAL_ALLOC specifies the initial malloc size when using the heap. It defaults to 200 bytes.
  • Allow realloc: By default when using the heap (-DINI_USE_STACK=0), inih allocates a fixed-sized buffer of INI_INITIAL_ALLOC bytes. To allow this to grow to INI_MAX_LINE bytes, doubling if needed, set -DINI_ALLOW_REALLOC=1.
  • Custom allocator: By default when using the heap, the standard library's malloc, free, and realloc functions are used; to use a custom allocator, specify -DINI_CUSTOM_ALLOCATOR=1 (and -DINI_USE_STACK=0). You must define and link functions named ini_malloc, ini_free, and (if INI_ALLOW_REALLOC is set) ini_realloc, which must have the same signatures as the stdlib.h memory allocation functions.

Simple example in C

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

typedef struct
{
    int version;
    const char* name;
    const char* email;
} configuration;

static int handler(void* user, const char* section, const char* name,
                   const char* value)
{
    configuration* pconfig = (configuration*)user;

    #define MATCH(s, n) strcmp(section, s) == 0 && strcmp(name, n) == 0
    if (MATCH("protocol", "version")) {
        pconfig->version = atoi(value);
    } else if (MATCH("user", "name")) {
        pconfig->name = strdup(value);
    } else if (MATCH("user", "email")) {
        pconfig->email = strdup(value);
    } else {
        return 0;  /* unknown section/name, error */
    }
    return 1;
}

int main(int argc, char* argv[])
{
    configuration config;

    if (ini_parse("test.ini", handler, &config) < 0) {
        printf("Can't load 'test.ini'\n");
        return 1;
    }
    printf("Config loaded from 'test.ini': version=%d, name=%s, email=%s\n",
        config.version, config.name, config.email);
    return 0;
}

C++ example

If you're into C++ and the STL, there is also an easy-to-use INIReader class that stores values in a map and lets you Get() them:

#include <iostream>
#include "INIReader.h"

int main()
{
    INIReader reader("../examples/test.ini");

    if (reader.ParseError() < 0) {
        std::cout << "Can't load 'test.ini'\n";
        return 1;
    }
    std::cout << "Config loaded from 'test.ini': version="
              << reader.GetInteger("protocol", "version", -1) << ", name="
              << reader.Get("user", "name", "UNKNOWN") << ", email="
              << reader.Get("user", "email", "UNKNOWN") << ", pi="
              << reader.GetReal("user", "pi", -1) << ", active="
              << reader.GetBoolean("user", "active", true) << "\n";
    return 0;
}

This simple C++ API works fine, but it's not very fully-fledged. I'm not planning to work more on the C++ API at the moment, so if you want a bit more power (for example GetSections() and GetFields() functions), see these forks:

Differences from ConfigParser

Some differences between inih and Python's ConfigParser standard library module:

  • INI name=value pairs given above any section headers are treated as valid items with no section (section name is an empty string). In ConfigParser having no section is an error.
  • Line continuations are handled with leading whitespace on continued lines (like ConfigParser). However, instead of concatenating continued lines together, they are treated as separate values for the same key (unlike ConfigParser).

Platform-specific notes

  • Windows/Win32 uses UTF-16 filenames natively, so to handle Unicode paths you need to call _wfopen() to open a file and then ini_parse_file() to parse it; inih does not include wchar_t or Unicode handling.

Meson notes

  • The meson.build file is not required to use or compile inih, its main purpose is for distributions.
  • By default Meson is set up for distro installation, but this behavior can be configured for embedded use cases:
    • with -Ddefault_library=static static libraries are built.
    • with -Ddistro_install=false libraries, headers and pkg-config files won't be installed.
    • with -Dwith_INIReader=false you can disable building the C++ library.
  • All compile-time options are implemented in Meson as well, you can take a look at meson_options.txt for their definition. These won't work if distro_install is set to true.
  • If you want to use inih for programs which may be shipped in a distro, consider linking against the shared libraries. The pkg-config entries are inih and INIReader.
  • In case you use inih as a Meson subproject, you can use the inih_dep and INIReader_dep dependency variables. You might want to set default_library=static and distro_install=false for the subproject. An official Wrap is provided on WrapDB.
  • For packagers: if you want to tag the version in the pkg-config file, you will need to do this downstream. Add version : '<version_as_int>', after the license tag in the project() function and version : meson.project_version(), after the soversion tag in both library() functions.

Building from vcpkg

You can build and install inih using vcpkg dependency manager:

git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install inih

The inih port in vcpkg is kept up to date by microsoft team members and community contributors. If the version is out of date, please create an issue or pull request on the vcpkg repository.

Related links

Comments
  • Switch from strncpy to memcpy in strcpy0 function

    Switch from strncpy to memcpy in strcpy0 function

    This pull request fixes a stringop-truncation warning. ini.c:78:5: warning: ‘strncpy’ output may be truncated copying 49 bytes from a string of length 199 [-Wstringop-truncation]

    opened by carmiker 12
  • Allow handler to be called on a key without '=' or ':'

    Allow handler to be called on a key without '=' or ':'

    The actual need on this is as follows. The INI file contains a special section containing all the sections in the file. That is used to validate the INI file itself. Eg

    [list all]
    section0
    section1
    
    [section0]
    key=val
    
    [section1]
    key=val
    

    For this to work, the keys in the list all section need to be passed to the handler, so they can be recorded and used later for the validation. This has been made configurable, so won't affect the default library behavior.

    Thanks.

    opened by weltling 11
  • Add visibility symbols

    Add visibility symbols

    They are required to properly build DLLs on Windows, and improve the quality of shared objects on Linux. See https://gcc.gnu.org/wiki/Visibility for details.

    This issue was first discovered here: https://github.com/mesonbuild/wrapdb/pull/340#issuecomment-1075102565

    CC @stephanlachnit and @eli-schwartz

    opened by Tachi107 9
  • Add option to call handler when a new section is encountered

    Add option to call handler when a new section is encountered

    Some programs have ini files with multiple sections that have the same name, which would make it very useful to know when a new section is encountered.

    This patch adds this ability as an option that's enabled by setting INI_CALL_HANDLER_ON_NEW_SECTION to 1.

    When enabled, the handler callback can check the name parameter. If it's NULL, then it was called because a new section was entered.

    opened by ksdhans 9
  • strncpy error in VS2013

    strncpy error in VS2013

    This library seems promising, with tests and all.

    When I tried your example in Visual Studio 2013, I got this error

    Error   1   error C4996: 'strncpy': This function or variable may be unsafe. Consider using strncpy_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.    c:\users\sturaroa\downloads\inih-r30\ini.c  56  1   IniParserTest
    

    I'd rather not use have to set permissive flags just for this bit.

    opened by AgostinoSturaro 9
  • New  'GetSections' method

    New 'GetSections' method

    Hello,
    
    We've made a new method, which we use in our applications which link with inih 
    library, to list the sections of the ini file.
    
    Please see it at:
    
    https://github.com/OSSystems/inih/commit/182f1e19eb99e188bf2f7e71fdb7ee8f4318610
    2
    
    and if possible merge it so it easy us to keep our CMake addition easy to 
    maintain :D
    

    Original issue reported on code.google.com by [email protected] on 5 Jul 2014 at 1:27

    Type-Defect Priority-Medium auto-migrated 
    opened by GoogleCodeExporter 9
  • array in ini file for ini parser stream to parse

    array in ini file for ini parser stream to parse

    Hi!:

    I have an array in a ini file like

    [section1]

    key1 = value1 key2 = value2 ..... lut_table = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 ......

    In the structure, it is defined as struct { ... int lut_table[16]; } for(i=0; i<16; i++) pconfig.lut_table[i] = atoi[multi_value] something?

    Can I implement something in the ini_parse_stream to read values for this array? any suggestions? Or something similar like simpleIni to have a key whic has multivalues?

    opened by chienhsinlin 8
  • Possible bug: ambiguous handling of continuations

    Possible bug: ambiguous handling of continuations

    What steps will reproduce the problem?
    1. Compile examples/ini_dump.c program (gcc examples/ini_dump.c ini.c
    2. Run output program with the INI file below (./a.out test.in)
    
    Sample INI file:
    
        [testing]
        key = value
                  plus a continuation
        key2 = value2
    
    Expected output:
    
        [testing]
        key = value
        plus a continuation
        key2 = value2
    
    Actual output:
    
        [testing]
        key = value
        key = plus a continuation
        key2 = value2
    
    Python's ConfigParser handles line continuations by appending the continuation 
    string onto the option value (prefixed with a newline).
    
    inih's method of handling continuations makes these two files equivalent (I 
    don't think they should be):
    
    File 1:
    
        [testing]
        key = value
              plus a continuation
    
    File 2:
    
        [testing]
        key = value
        key = plus a continuation
    

    Original issue reported on code.google.com by [email protected] on 11 Mar 2012 at 11:33

    Type-Defect Priority-Medium auto-migrated 
    opened by GoogleCodeExporter 8
  • Makefile for building inih as static library

    Makefile for building inih as static library

    Hello,
    
    I am packaging dunst software into Fedora and our rules does not allow 
    embedding libraries. Would you accept this Makefile so linux distributions 
    could make static packages of your library?
    
    It does not have to be called "Makefile", I would be fine with 
    "Makefile.static" or "Makefile.dist". It would be also possible to include the 
    file in the extra/ directory (but some paths would need to be changed).
    
    More details here: https://fedorahosted.org/fpc/ticket/216
    
    Thank you in advance. This is the Makefile (attaching it as well because of 
    TABs):
    
    # 
    # Simple makefile to build inih as static library.
    #
    
    SRC = ini.c
    OBJ = $(SRC:.c=.o)
    OUT = libinih.a
    INCLUDES = -I.
    CCFLAGS = -g -O2
    CCC = g++
    LDFLAGS = -g
    
    .SUFFIXES: .cpp
    
    default: $(OUT)
    
    .cpp.o:
        $(CCC) $(INCLUDES) $(CCFLAGS) $(EXTRACCFLAGS) -c $< -o [email protected]
    
    $(OUT): $(OBJ)
        ar rcs $(OUT) $(OBJ)
    
    clean:
        rm -f $(OBJ) $(OUT)
    

    Original issue reported on code.google.com by [email protected] on 8 Oct 2012 at 2:38

    Attachments:

    Type-Defect Priority-Medium auto-migrated 
    opened by GoogleCodeExporter 7
  • BOM support

    BOM support

    Seems that ini files with BOM header is not currently supported. Could you 
    support this, please?
    
    
    Thanks!
    

    Original issue reported on code.google.com by xuhdev on 14 Jun 2012 at 9:24

    Type-Defect Priority-Medium auto-migrated 
    opened by GoogleCodeExporter 7
  • Added tipi.build support and a simple usage example

    Added tipi.build support and a simple usage example

    Hello, Yannic from tipi.build here,

    I just added tipi support to your project and was wondering if you'd like to merge so everyone gets a new way of using your project.

    I tested the project (both for project dev and as dep) for Linux, MacOS and Windows (both clang and MSVC builds btw) and it seems to work nicely.

    If there's any issue or if you have any question with this I'll be happy to sort it out

    Best from Zürich, Yannic

    opened by pysco68 6
  • Fixed handling of long strings when using INI_USE_STACK

    Fixed handling of long strings when using INI_USE_STACK

    Undefined behavior occurred if the incoming .ini file contains a line that is longer than INI_MAX_LINE with the INI_USE_STACK option. In such a case, it is safe to abort parsing even if INI_STOP_ON_FIRST_ERROR is not set.

    See https://github.com/benhoyt/inih/issues/145 for the details

    Signed-off-by: Mikhail Khachayants [email protected]

    opened by tyler92 2
  • Seems to not discard the rest of a long line?

    Seems to not discard the rest of a long line?

    The problem:

    The issue assumes we are dealing with a long line in an ini file.

    In line 136, reader (fgets) will read max_line chars. If using a heap, then in line 139 and forward, the heap will resize and all the rest of the line will be read:

    https://github.com/benhoyt/inih/blob/5e1d9e2625842dddb3f9c086a50f22e4f45dfc2b/ini.c#L136-L141

    But, in the default case with a stack (fixed size array), fgets will read max_line and do nothing with the rest of the line, which I think will stay in the input stream. Then, in the next iteration of while on line 136, fgets will continue to read that rest of the line, but inih treats those text as the next line. The code will most likely find no : or = in those text, thus report an error on line #(line number of the long line + 1).

    Discussion:

    So, is this expected behavior, or should inih discard the rest of a lone line? The latter might be something like this:

        while (reader(line, (int)max_line, stream) != NULL) {
    #if INI_ALLOW_REALLOC && !INI_USE_STACK
    ... ...
    #else
    if (strchr(line, '\n') == NULL)
        while (fgetc(stream) != '\n')
            ;
    #endif
    
    opened by xlucn 4
Releases(r56)
Owner
Ben Hoyt
By day I’m a software engineer at Canonical, by night a Go hacker and husband/father.
Ben Hoyt
Cross-platform C++ library providing a simple API to read and write INI-style configuration files

simpleini A cross-platform library that provides a simple API to read and write INI-style configuration files. It supports data files in ASCII, MBCS a

Brodie Thiesfield 797 Dec 28, 2022
C++20 single-header library for embedding INI configs

ini-config A single-header library that converts INI-formatted string literals to a key-value pair list at compile-time. Requires C++20; tested on gcc

clyne 55 Nov 26, 2022
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
Header-only TOML config file parser and serializer for C++17 (and later!).

toml++ homepage ✨ This README is fine, but the toml++ homepage is better. ✨ Library features Header-only Supports the latest TOML release (v1.0.0), pl

Mark Gillard 965 Dec 29, 2022
config-loader is a static reflection framework written in C++17 from parse configuration file to native data structure.

config-loader is a static reflection framework written in C++17 from parse configuration file to native data structure.

Netcan 121 Dec 15, 2022
Simple .INI file parser in C, good for embedded systems

inih (INI Not Invented Here) inih (INI Not Invented Here) is a simple .INI file parser written in C. It's only a couple of pages of code, and it was d

Ben Hoyt 1.9k Jan 2, 2023
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
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
BLLIP reranking parser (also known as Charniak-Johnson parser, Charniak parser, Brown reranking parser) See http://pypi.python.org/pypi/bllipparser/ for Python module.

BLLIP Reranking Parser Copyright Mark Johnson, Eugene Charniak, 24th November 2005 --- August 2006 We request acknowledgement in any publications that

Brown Laboratory for Linguistic Information Processing 218 Dec 17, 2022
BLLIP reranking parser (also known as Charniak-Johnson parser, Charniak parser, Brown reranking parser)

BLLIP reranking parser (also known as Charniak-Johnson parser, Charniak parser, Brown reranking parser)

Brown Laboratory for Linguistic Information Processing 218 Dec 17, 2022
Lab2: using a physical embedded systems to interact with virtual embedded systems.

Lab2: dotDevice EmSys Autumn 2021 In this lab you will use your TinyPico to interact with a virtual embedded system. Current Virtual Lab URL: [http://

Shane Fleming 1 Oct 20, 2021
A small and portable INI file library with read/write support

minIni minIni is a portable and configurable library for reading and writing ".INI" files. At just below 900 lines of commented source code, minIni tr

Thiadmer Riemersma 293 Dec 29, 2022
JSON parser and generator for C/C++ with scanf/printf like interface. Targeting embedded systems.

JSON parser and emitter for C/C++ Features ISO C and ISO C++ compliant portable code Very small footprint No dependencies json_scanf() scans a string

Cesanta Software 637 Dec 30, 2022
A place to collaborate on code for the Embedded.fm book club. Currently reading "STM32 ARM Programming for Embedded Systems".

Welcome to the Book Club Code site! This is a place for the Embedded.fm book club to collaborate and learn together. Repo Structure Guide Top-level fo

Peter Griffin 11 Jul 21, 2022
Low dependency(C++11 STL only), good portability, header-only, deep neural networks for embedded

LKYDeepNN LKYDeepNN 可訓練的深度類神經網路 (Deep Neural Network) 函式庫。 輕量,核心部份只依賴 C++11 標準函式庫,低相依性、好移植,方便在嵌入式系統上使用。 Class diagram 附有訓練視覺化 demo 程式 訓練視覺化程式以 OpenCV

Lin Kao-Yuan 44 Nov 7, 2022
Cross-platform C++ library providing a simple API to read and write INI-style configuration files

simpleini A cross-platform library that provides a simple API to read and write INI-style configuration files. It supports data files in ASCII, MBCS a

Brodie Thiesfield 797 Dec 28, 2022
Open source file system for small embedded systems

STORfs Open Source File System Release Version 1.0.2 Created by: KrauseGLOBAL Solutions, LLC What is STORfs? STORfs is an open source flash file syste

null 17 Jul 26, 2022
Generic single-file implementations of AVL tree in C and C++ suitable for deeply embedded systems

Cavl Generic single-file implementation of AVL tree suitable for deeply embedded systems. Simply copy cavl.h or cavl.hpp (depending on which language

Pavel Kirienko 8 Dec 27, 2022
C++20 single-header library for embedding INI configs

ini-config A single-header library that converts INI-formatted string literals to a key-value pair list at compile-time. Requires C++20; tested on gcc

clyne 55 Nov 26, 2022
Blog post on using a custom Bash builtin to parse INI config files

Writing a Bash Builtin in C to Parse INI Configs Why Not Just Parse INI Configs With Bash? Shell languages such as Bash excel at certain tasks, such a

Jesse Hathaway 16 Oct 8, 2022