Skip to content

Latest commit

 

History

History
615 lines (451 loc) · 25.2 KB

File metadata and controls

615 lines (451 loc) · 25.2 KB

ssfini — INI File Parser/Generator

SSF | Codecs

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 index parameter (0-based) to select among them.
  • Values cannot contain whitespace; quoted strings are not supported.
  • Pass NULL for the section parameter to operate in the global (no-section) scope.
  • Generator functions require *iniLen to be initialized to 0 before 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

Definitions

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

Functions

Function Description
e.g. bool SSFINIIsSectionPresent(ini, section) Check whether a named section exists
e.g. bool SSFINIIsNameValuePresent(ini, section, name, index) Check whether a name/value pair exists
e.g. bool SSFINIGetStrValue(ini, section, name, index, out, outSize, outLen) Get a value as a string
e.g. bool SSFINIGetBoolValue(ini, section, name, index, out) Get a value as a boolean
e.g. bool SSFINIGetIntValue(ini, section, name, index, out) Get a value as a signed 64-bit integer
e.g. bool SSFINIPrintComment(ini, iniSize, iniLen, text, commentType, lineEnding) Append a comment line to an INI output buffer
e.g. bool SSFINIPrintSection(ini, iniSize, iniLen, section, lineEnding) Append a section header line to an INI output buffer
e.g. bool SSFINIPrintNameStrValue(ini, iniSize, iniLen, name, value, lineEnding) Append a string name=value line
e.g. bool SSFINIPrintNameBoolValue(ini, iniSize, iniLen, name, value, boolType, lineEnding) Append a boolean name=value line
e.g. bool SSFINIPrintNameIntValue(ini, iniSize, iniLen, name, value, lineEnding) Append an integer name=value line
e.g. bool SSFINIGObjCreate(ini, gobj, maxChildren) Convert an INI string to a gobj tree (SSF_INI_GOBJ_ENABLE)
e.g. bool SSFINIGObjPrint(gobj, ini, iniSize, iniLen, boolType, lineEnding) Convert a gobj tree to an INI string (SSF_INI_GOBJ_ENABLE)

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_STR children of the root, labeled with the name.
  • Each section becomes an SSF_OBJ_TYPE_OBJECT child of the root, labeled with the section name. Its name=value pairs become SSF_OBJ_TYPE_STR children 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_OBJECT are 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);