INI file parser and generator supporting string, boolean, and integer value types.
The parser searches a null-terminated INI string in memory for sections, names, and values.
The generator appends INI text (comments, section headers, and name=value lines) to a
caller-supplied buffer. Both sides use bounded buffers and return false rather than
truncating or overflowing.
Dependencies | Notes | Configuration | API Summary | Function Reference
↑ Dependencies
↑ Notes
- Section and name comparisons are case-sensitive.
- Multiple entries with the same name within a section are allowed; use the
indexparameter (0-based) to select among them. - Values cannot contain whitespace; quoted strings are not supported.
- Pass
NULLfor thesectionparameter to operate in the global (no-section) scope. - Generator functions require
*iniLento be initialized to0before the first call and updated by each successive call; the buffer is always null-terminated on success.
↑ Configuration
The following options are defined in ssfoptions.h:
| Option | Default | Description |
|---|---|---|
SSF_INI_GOBJ_ENABLE |
1 |
Set to 1 to enable SSFINIGObjCreate() and SSFINIGObjPrint() INI/gobj conversion functions. Set to 0 to exclude them and remove the ssfgobj dependency. |
SSF_INI_GOBJ_CONFIG_MAX_STR_SIZE |
256 |
Maximum length in bytes of any section name, key name, or value string during INI/gobj conversion. |
↑ API Summary
| Symbol | Kind | Description |
|---|---|---|
SSFINILineEnd_t |
Enum | Line-ending style for generator functions |
SSF_INI_LF |
Enum value | SSFINILineEnd_t — Unix \n line ending |
SSF_INI_CRLF |
Enum value | SSFINILineEnd_t — Windows \r\n line ending |
SSFINIBool_t |
Enum | Boolean text format for SSFINIPrintNameBoolValue() |
SSF_INI_BOOL_1_0 |
Enum value | SSFINIBool_t — writes 1 / 0 |
SSF_INI_BOOL_YES_NO |
Enum value | SSFINIBool_t — writes yes / no |
SSF_INI_BOOL_ON_OFF |
Enum value | SSFINIBool_t — writes on / off |
SSF_INI_BOOL_TRUE_FALSE |
Enum value | SSFINIBool_t — writes true / false |
SSFINIComment_t |
Enum | Comment prefix character for SSFINIPrintComment() |
SSF_INI_COMMENT_SEMI |
Enum value | SSFINIComment_t — ; prefix |
SSF_INI_COMMENT_HASH |
Enum value | SSFINIComment_t — # prefix |
SSF_INI_COMMENT_NONE |
Enum value | SSFINIComment_t — no prefix |
↑ Function Reference
bool SSFINIIsSectionPresent(SSFCStrIn_t ini, SSFCStrIn_t section);Searches a null-terminated INI string for a section header whose name exactly matches
section. The comparison is case-sensitive.
| Parameter | Direction | Type | Description |
|---|---|---|---|
ini |
in | const char * |
Pointer to the null-terminated INI string to search. Must not be NULL. |
section |
in | const char * |
Null-terminated section name to find (without brackets). Must not be NULL. |
Returns: true if a matching [section] header is found; false otherwise.
The parser examples below all use this INI source string:
const char ini[] = "global=42\r\n"
"[section]\r\n"
"name=yes\r\n"
"name=0\r\n"
"host=localhost\r\n";SSFINIIsSectionPresent(ini, "section"); /* returns true */
SSFINIIsSectionPresent(ini, "Section"); /* returns false — case-sensitive */
SSFINIIsSectionPresent(ini, "other"); /* returns false */bool SSFINIIsNameValuePresent(SSFCStrIn_t ini, SSFCStrIn_t section, SSFCStrIn_t name,
uint8_t index);Checks whether a name/value entry with the given name exists within the specified section.
The index parameter selects among multiple entries with the same name (0-based).
| Parameter | Direction | Type | Description |
|---|---|---|---|
ini |
in | const char * |
Pointer to the null-terminated INI string. Must not be NULL. |
section |
in | const char * |
Null-terminated section name to search within. Pass NULL to search the global (no-section) scope. |
name |
in | const char * |
Null-terminated name to find. Must not be NULL. |
index |
in | uint8_t |
0-based occurrence index among entries with the same name within the section. |
Returns: true if the index-th occurrence of name exists in the specified section; false otherwise.
/* Global scope (NULL section) */
SSFINIIsNameValuePresent(ini, NULL, "global", 0); /* returns true */
SSFINIIsNameValuePresent(ini, NULL, "global", 1); /* returns false — only one occurrence */
/* Named section — "name" appears twice, index 0 and 1 */
SSFINIIsNameValuePresent(ini, "section", "name", 0); /* returns true */
SSFINIIsNameValuePresent(ini, "section", "name", 1); /* returns true */
SSFINIIsNameValuePresent(ini, "section", "name", 2); /* returns false */bool SSFINIGetStrValue(SSFCStrIn_t ini, SSFCStrIn_t section, SSFCStrIn_t name, uint8_t index,
SSFCStrOut_t out, size_t outSize, size_t *outLen);Retrieves the string value of the index-th occurrence of name within section, copying
it as a null-terminated string into out.
| Parameter | Direction | Type | Description |
|---|---|---|---|
ini |
in | const char * |
Pointer to the null-terminated INI string. Must not be NULL. |
section |
in | const char * |
Null-terminated section name. Pass NULL for the global scope. |
name |
in | const char * |
Null-terminated name to look up. Must not be NULL. |
index |
in | uint8_t |
0-based occurrence index. |
out |
out | char * |
Buffer receiving the null-terminated value string. Must not be NULL. |
outSize |
in | size_t |
Allocated size of out in bytes. Must be large enough for the value plus null terminator. |
outLen |
out (opt) | size_t * |
If not NULL, receives the length of the value string (excluding null terminator). |
Returns: true if the entry was found and the value copied into out; false if not found or outSize is too small.
char val[32];
size_t valLen;
/* First occurrence of "name" in [section] → "yes" */
if (SSFINIGetStrValue(ini, "section", "name", 0, val, sizeof(val), &valLen))
{
/* val == "yes", valLen == 3 */
}
/* Second occurrence of "name" in [section] → "0" */
if (SSFINIGetStrValue(ini, "section", "name", 1, val, sizeof(val), NULL))
{
/* val == "0" */
}bool SSFINIGetBoolValue(SSFCStrIn_t ini, SSFCStrIn_t section, SSFCStrIn_t name, uint8_t index,
bool *out);Retrieves the boolean value of the index-th occurrence of name within section. Recognized
true values: 1, yes, on, true (case-insensitive). Recognized false values: 0, no,
off, false (case-insensitive).
| Parameter | Direction | Type | Description |
|---|---|---|---|
ini |
in | const char * |
Pointer to the null-terminated INI string. Must not be NULL. |
section |
in | const char * |
Null-terminated section name. Pass NULL for the global scope. |
name |
in | const char * |
Null-terminated name to look up. Must not be NULL. |
index |
in | uint8_t |
0-based occurrence index. |
out |
out | bool * |
Receives the parsed boolean value. Must not be NULL. |
Returns: true if the entry was found and the value is a recognized boolean string; false otherwise.
bool b;
/* "name=yes" at index 0 */
if (SSFINIGetBoolValue(ini, "section", "name", 0, &b))
{
/* b == true */
}
/* "name=0" at index 1 */
if (SSFINIGetBoolValue(ini, "section", "name", 1, &b))
{
/* b == false */
}bool SSFINIGetIntValue(SSFCStrIn_t ini, SSFCStrIn_t section, SSFCStrIn_t name, uint8_t index,
int64_t *out);Retrieves the integer value of the index-th occurrence of name within section, parsing
it as a signed 64-bit decimal integer.
| Parameter | Direction | Type | Description |
|---|---|---|---|
ini |
in | const char * |
Pointer to the null-terminated INI string. Must not be NULL. |
section |
in | const char * |
Null-terminated section name. Pass NULL for the global scope. |
name |
in | const char * |
Null-terminated name to look up. Must not be NULL. |
index |
in | uint8_t |
0-based occurrence index. |
out |
out | int64_t * |
Receives the parsed integer value. Must not be NULL. |
Returns: true if the entry was found and parsed as a valid integer; false otherwise.
int64_t n;
/* "global=42" in global scope */
if (SSFINIGetIntValue(ini, NULL, "global", 0, &n))
{
/* n == 42 */
}
/* "name=0" at index 1 in [section] */
if (SSFINIGetIntValue(ini, "section", "name", 1, &n))
{
/* n == 0 */
}bool SSFINIPrintComment(SSFCStrOut_t ini, size_t iniSize, size_t *iniLen, SSFCStrIn_t text,
SSFINIComment_t commentType, SSFINILineEnd_t lineEnding);Appends a comment line to the INI output buffer. The comment character is selected by
commentType. *iniLen must be initialized to 0 before the first generator call and is
updated by each successive call.
| Parameter | Direction | Type | Description |
|---|---|---|---|
ini |
in-out | char * |
INI output buffer. Must not be NULL. Must be null-terminated. |
iniSize |
in | size_t |
Total allocated size of ini in bytes. |
iniLen |
in-out | size_t * |
Current length of text in ini (excluding null terminator). Updated on success. Must not be NULL. |
text |
in | const char * |
Null-terminated comment text (without the comment character). Must not be NULL. |
commentType |
in | SSFINIComment_t |
Comment prefix: SSF_INI_COMMENT_SEMI for ;, SSF_INI_COMMENT_HASH for #, SSF_INI_COMMENT_NONE for no prefix. |
lineEnding |
in | SSFINILineEnd_t |
Line ending style: SSF_INI_LF for \n, SSF_INI_CRLF for \r\n. |
Returns: true if the comment line was appended; false if the buffer is too small.
char buf[128];
size_t len = 0;
SSFINIPrintComment(buf, sizeof(buf), &len, " generated config", SSF_INI_COMMENT_SEMI, SSF_INI_CRLF);
/* buf == "; generated config\r\n" */
SSFINIPrintComment(buf, sizeof(buf), &len, " also a comment", SSF_INI_COMMENT_HASH, SSF_INI_CRLF);
/* buf == "; generated config\r\n# also a comment\r\n" */bool SSFINIPrintSection(SSFCStrOut_t ini, size_t iniSize, size_t *iniLen, SSFCStrIn_t section,
SSFINILineEnd_t lineEnding);Appends a section header line ([section]) to the INI output buffer.
| Parameter | Direction | Type | Description |
|---|---|---|---|
ini |
in-out | char * |
INI output buffer. Must not be NULL. Must be null-terminated. |
iniSize |
in | size_t |
Total allocated size of ini in bytes. |
iniLen |
in-out | size_t * |
Current length of text in ini. Updated on success. Must not be NULL. |
section |
in | const char * |
Null-terminated section name (without brackets). Must not be NULL. |
lineEnding |
in | SSFINILineEnd_t |
Line ending style: SSF_INI_LF or SSF_INI_CRLF. |
Returns: true if the section header was appended; false if the buffer is too small.
char buf[128];
size_t len = 0;
SSFINIPrintSection(buf, sizeof(buf), &len, "network", SSF_INI_CRLF);
/* buf == "[network]\r\n" */bool SSFINIPrintNameStrValue(SSFCStrOut_t ini, size_t iniSize, size_t *iniLen, SSFCStrIn_t name,
SSFCStrIn_t value, SSFINILineEnd_t lineEnding);Appends a name=value line with a string value to the INI output buffer.
| Parameter | Direction | Type | Description |
|---|---|---|---|
ini |
in-out | char * |
INI output buffer. Must not be NULL. Must be null-terminated. |
iniSize |
in | size_t |
Total allocated size of ini in bytes. |
iniLen |
in-out | size_t * |
Current length of text in ini. Updated on success. Must not be NULL. |
name |
in | const char * |
Null-terminated name string. Must not be NULL. |
value |
in | const char * |
Null-terminated value string. Must not be NULL. |
lineEnding |
in | SSFINILineEnd_t |
Line ending style: SSF_INI_LF or SSF_INI_CRLF. |
Returns: true if the line was appended; false if the buffer is too small.
char buf[128];
size_t len = 0;
SSFINIPrintSection (buf, sizeof(buf), &len, "network", SSF_INI_CRLF);
SSFINIPrintNameStrValue(buf, sizeof(buf), &len, "host", "localhost", SSF_INI_CRLF);
/* buf == "[network]\r\nhost=localhost\r\n" */bool SSFINIPrintNameBoolValue(SSFCStrOut_t ini, size_t iniSize, size_t *iniLen, SSFCStrIn_t name,
bool value, SSFINIBool_t boolType, SSFINILineEnd_t lineEnding);Appends a name=value line with a boolean value to the INI output buffer. The text
representation is selected by boolType.
| Parameter | Direction | Type | Description |
|---|---|---|---|
ini |
in-out | char * |
INI output buffer. Must not be NULL. Must be null-terminated. |
iniSize |
in | size_t |
Total allocated size of ini in bytes. |
iniLen |
in-out | size_t * |
Current length of text in ini. Updated on success. Must not be NULL. |
name |
in | const char * |
Null-terminated name string. Must not be NULL. |
value |
in | bool |
Boolean value to write. |
boolType |
in | SSFINIBool_t |
Text format: SSF_INI_BOOL_1_0, SSF_INI_BOOL_YES_NO, SSF_INI_BOOL_ON_OFF, or SSF_INI_BOOL_TRUE_FALSE. |
lineEnding |
in | SSFINILineEnd_t |
Line ending style: SSF_INI_LF or SSF_INI_CRLF. |
Returns: true if the line was appended; false if the buffer is too small.
char buf[128];
size_t len = 0;
SSFINIPrintSection (buf, sizeof(buf), &len, "network", SSF_INI_CRLF);
SSFINIPrintNameBoolValue(buf, sizeof(buf), &len, "enabled", true, SSF_INI_BOOL_YES_NO, SSF_INI_CRLF);
SSFINIPrintNameBoolValue(buf, sizeof(buf), &len, "debug", false, SSF_INI_BOOL_TRUE_FALSE, SSF_INI_CRLF);
/* buf == "[network]\r\nenabled=yes\r\ndebug=false\r\n" */bool SSFINIPrintNameIntValue(SSFCStrOut_t ini, size_t iniSize, size_t *iniLen, SSFCStrIn_t name,
int64_t value, SSFINILineEnd_t lineEnding);Appends a name=value line with a signed 64-bit integer value to the INI output buffer.
| Parameter | Direction | Type | Description |
|---|---|---|---|
ini |
in-out | char * |
INI output buffer. Must not be NULL. Must be null-terminated. |
iniSize |
in | size_t |
Total allocated size of ini in bytes. |
iniLen |
in-out | size_t * |
Current length of text in ini. Updated on success. Must not be NULL. |
name |
in | const char * |
Null-terminated name string. Must not be NULL. |
value |
in | int64_t |
Signed integer value to write. |
lineEnding |
in | SSFINILineEnd_t |
Line ending style: SSF_INI_LF or SSF_INI_CRLF. |
Returns: true if the line was appended; false if the buffer is too small.
char buf[128];
size_t len = 0;
SSFINIPrintSection (buf, sizeof(buf), &len, "network", SSF_INI_CRLF);
SSFINIPrintNameIntValue(buf, sizeof(buf), &len, "port", 8080, SSF_INI_CRLF);
SSFINIPrintNameIntValue(buf, sizeof(buf), &len, "timeout", -1, SSF_INI_CRLF);
/* buf == "[network]\r\nport=8080\r\ntimeout=-1\r\n" */Requires SSF_INI_GOBJ_ENABLE == 1.
bool SSFINIGObjCreate(SSFCStrIn_t ini, SSFGObj_t **gobj, uint16_t maxChildren);Parses a null-terminated INI string and builds a generic object tree (SSFGObj_t) representing
its contents. On success, *gobj points to a newly allocated root object that must be freed
with SSFGObjDeInit().
The resulting tree has the following structure:
- The root node is an
SSF_OBJ_TYPE_OBJECT. - Global name=value pairs (before the first section header) become
SSF_OBJ_TYPE_STRchildren of the root, labeled with the name. - Each section becomes an
SSF_OBJ_TYPE_OBJECTchild of the root, labeled with the section name. Its name=value pairs becomeSSF_OBJ_TYPE_STRchildren labeled with the name. - Duplicate section headers are merged into a single object node; entries from all occurrences of that section appear as children.
- All values are stored as strings. Comments are ignored.
| Parameter | Direction | Type | Description |
|---|---|---|---|
ini |
in | const char * |
Null-terminated INI string to parse. Must not be NULL. |
gobj |
out | SSFGObj_t ** |
Receives the root of the newly allocated gobj tree. Must not be NULL. |
maxChildren |
in | uint16_t |
Maximum number of children for each container node (root and sections). |
Returns: true if the INI was successfully converted; false on allocation failure or if
any section name, key name, or value exceeds SSF_INI_GOBJ_CONFIG_MAX_STR_SIZE.
const char ini[] = "global=42\n"
"[section]\n"
"host=localhost\n"
"port=8080\n";
SSFGObj_t *gobj = NULL;
if (SSFINIGObjCreate(ini, &gobj, 8))
{
SSFGObj_t *parent = NULL;
SSFGObj_t *child = NULL;
SSFCStrIn_t path[SSF_GOBJ_CONFIG_MAX_IN_DEPTH + 1] = { NULL };
char val[64];
/* Read a global value */
path[0] = "global";
SSFGObjFindPath(gobj, path, &parent, &child);
SSFGObjGetString(child, val, sizeof(val));
/* val == "42" */
/* Read a value inside a section */
memset(path, 0, sizeof(path));
path[0] = "section"; path[1] = "host";
parent = NULL; child = NULL;
SSFGObjFindPath(gobj, path, &parent, &child);
SSFGObjGetString(child, val, sizeof(val));
/* val == "localhost" */
SSFGObjDeInit(&gobj);
}Requires SSF_INI_GOBJ_ENABLE == 1.
bool SSFINIGObjPrint(SSFGObj_t *gobj, SSFCStrOut_t ini, size_t iniSize, size_t *iniLen,
SSFINIBool_t boolType, SSFINILineEnd_t lineEnding);Serializes a generic object tree into a null-terminated INI string. The gobj tree must follow
the structure produced by SSFINIGObjCreate():
- The root must be
SSF_OBJ_TYPE_OBJECT. - Direct children of the root that are leaf types (
SSF_OBJ_TYPE_STR,SSF_OBJ_TYPE_INT,SSF_OBJ_TYPE_BOOL) are printed as global name=value lines. - Direct children that are
SSF_OBJ_TYPE_OBJECTare printed as[section]headers, with their leaf children printed as name=value lines under the section.
Global entries are printed first, followed by sections in child-list order.
| Parameter | Direction | Type | Description |
|---|---|---|---|
gobj |
in | SSFGObj_t * |
Root of the gobj tree. Must not be NULL. Must be SSF_OBJ_TYPE_OBJECT. |
ini |
in-out | char * |
INI output buffer. Must not be NULL. |
iniSize |
in | size_t |
Total allocated size of ini in bytes. Must be > 0. |
iniLen |
in-out | size_t * |
Current length of text in ini. Must be initialized to 0 before the first call. Updated on success. Must not be NULL. |
boolType |
in | SSFINIBool_t |
Text format for SSF_OBJ_TYPE_BOOL values. |
lineEnding |
in | SSFINILineEnd_t |
Line ending style: SSF_INI_LF or SSF_INI_CRLF. |
Returns: true if the entire tree was serialized into the buffer; false if the buffer is
too small, the root is not an object, or a child has an unsupported type.
/* Build a gobj tree */
SSFGObj_t *root = NULL;
SSFGObj_t *sec = NULL;
SSFGObj_t *child = NULL;
SSFGObjInit(&root, 8);
SSFGObjSetObject(root);
SSFGObjInit(&sec, 8);
SSFGObjSetLabel(sec, "network");
SSFGObjSetObject(sec);
child = NULL;
SSFGObjInit(&child, 0);
SSFGObjSetLabel(child, "host");
SSFGObjSetString(child, "localhost");
SSFGObjInsertChild(sec, child);
child = NULL;
SSFGObjInit(&child, 0);
SSFGObjSetLabel(child, "port");
SSFGObjSetInt(child, 8080);
SSFGObjInsertChild(sec, child);
SSFGObjInsertChild(root, sec);
/* Serialize to INI */
char buf[128];
size_t len = 0;
SSFINIGObjPrint(root, buf, sizeof(buf), &len, SSF_INI_BOOL_TRUE_FALSE, SSF_INI_LF);
/* buf == "[network]\nhost=localhost\nport=8080\n" */
SSFGObjDeInit(&root);