Created
October 11, 2018 16:36
-
-
Save dvdhrm/5dede9c9b5aa8196dcb9afd5a5621991 to your computer and use it in GitHub Desktop.
API Proposal for c-ini
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#pragma once | |
/** | |
* Ini-File Handling | |
* | |
* XXX | |
* | |
* Possible extensions: | |
* | |
* * For now the API does not include serializers / writers, but was written | |
* to allow for seamless addition of such calls. Ini-Files are | |
* human-readable files, and as such there rarely is the need to write them | |
* programmatically. If the need ever arises, we will have to extent the API | |
* to provide serializers and modifiers. | |
* | |
* * Several different INI formats exist. For now, we only support the | |
* desktop-entry-specification as released by XDG / freedesktop.org. Other | |
* formats should be straightforward to add. | |
* | |
* * The glib-keyfile implementation has a set of extensions over the XDG | |
* specification. We might consider implementing these. | |
* | |
* * Ignore a single trailing '\r'. This is ignored both as "\r\n" as well | |
* as at the end of the file in case there is no missing newline. | |
* | |
* * Whitespace are ignored at the beginning of all lines (including | |
* 'blank' lines and comments). Additionally, trailing a group SPACE and | |
* HORIZONTAL TAB are ignored (possibly a bug and meant to ignore all | |
* whitespace). | |
* | |
* Whitespace according to glib are independent of any locale, and they | |
* currently include: | |
* | |
* 0x09: HORIZONTAL TAB (\t) | |
* 0x0a: LINE FEED (\n) | |
* 0x0c: FORM FEED (\x0c) | |
* 0x0d: CARRIAGE RETURN (\r) | |
* 0x20: SPACE ( ) | |
* | |
* * An 'Encoding=' key is interpreted in the first-group and first-group | |
* only. Anything but 'UTF-8' is rejected. | |
* There should be little reason to support this feature. | |
* | |
* * Identifiers are not restricted to ASCII. The restrictions are: | |
* | |
* * Group names must be non-empty, must not contain '[', ']', nor ASCII | |
* control characters. Invalid UTF-8 is accepted, though. | |
* | |
* * Keys must be non-empty, must not contain '[', ']', '=', nor spaces. | |
* Invalid UTF-8 is accepted, though. | |
* A key might have a trailing locale specifier enclosed in brackets, | |
* which must only contain alphanumeric codepoints, as well as '@', | |
* '.', '_', '-'. | |
* | |
* * The current parsers assume the data source is trusted. Meaning, while it | |
* does correctly verify validity of all content, it does not enforce limits | |
* on data lengths in any way. If the data source is not trusted, you would | |
* want to extend the parsers to refuse files with overlong entities, or | |
* overlong extents. | |
*/ | |
#ifdef __cplusplus | |
extern "C" { | |
#endif | |
#include <inttypes.h> | |
#include <stdlib.h> | |
typedef struct CIniDomain CIniDomain; | |
typedef struct CIniEntry CIniEntry; | |
typedef struct CIniGroup CIniGroup; | |
typedef struct CIniReader CIniReader; | |
enum { | |
_C_INI_E_SUCCESS, | |
C_INI_E_DUPLICATE, | |
_C_INI_E_N, | |
}; | |
/* entries */ | |
CIniEntry *c_ini_entry_ref(CIniEntry *entry); | |
CIniEntry *c_ini_entry_unref(CIniEntry *entry); | |
CIniEntry *c_ini_entry_next(CIniEntry *entry); | |
CIniEntry *c_ini_entry_previous(CIniEntry *entry); | |
const char *c_ini_entry_get_key(CIniEntry *entry, size_t *n_keyp); | |
const char *c_ini_entry_get_value(CIniEntry *entry, size_t *n_valuep); | |
/* groups */ | |
CIniGroup *c_ini_group_ref(CIniGroup *group); | |
CIniGroup *c_ini_group_unref(CIniGroup *group); | |
CIniGroup *c_ini_group_next(CIniGroup *group); | |
CIniGroup *c_ini_group_previous(CIniGroup *group); | |
const char *c_ini_group_get_label(CIniGroup *group, size_t *n_groupp); | |
CIniEntry *c_ini_group_iterate(CIniGroup *group); | |
CIniEntry *c_ini_group_find(CIniGroup *group, const char *label, ssize_t n_label); | |
/* domains */ | |
CIniDomain *c_ini_domain_ref(CIniDomain *domain); | |
CIniDomain *c_ini_domain_unref(CIniDomain *domain); | |
CIniGroup *c_ini_domain_iterate(CIniDomain *domain); | |
CIniGroup *c_ini_domain_find(CIniDomain *domain, const char *label, ssize_t n_label); | |
/* readers */ | |
int c_ini_reader_new_xdg(CIniReader **readerp); | |
CIniReader *c_ini_reader_free(CIniReader *reader); | |
int c_ini_reader_feed(CIniReader *reader, const uint8_t *data, size_t n_data); | |
int c_ini_reader_seal(CIniReader *reader, CIniDomain **domainp); | |
int c_ini_reader_parse_xdg(CIniDomain **domainp, const uint8_t *data, size_t n_data); | |
/* inline helpers */ | |
static inline void c_ini_entry_unrefp(CIniEntry **entry) { | |
if (*entry) | |
c_ini_entry_unref(*entry); | |
} | |
static inline void c_ini_group_unrefp(CIniGroup **group) { | |
if (*group) | |
c_ini_group_unref(*group); | |
} | |
static inline void c_ini_domain_unrefp(CIniDomain **domain) { | |
if (*domain) | |
c_ini_domain_unref(*domain); | |
} | |
static inline void c_ini_reader_freep(CIniReader **reader) { | |
if (*reader) | |
c_ini_reader_free(*reader); | |
} | |
#ifdef __cplusplus | |
} | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment