aboutsummaryrefslogtreecommitdiff
path: root/src/ini.c
diff options
context:
space:
mode:
authorHarry Jeffery <harry@exec64.co.uk>2017-09-23 00:16:38 +0100
committerHarry Jeffery <harry@exec64.co.uk>2017-11-23 21:34:11 +0000
commit4579df9114c00075166b59a67724ec7472facb27 (patch)
tree0da6d65a35864d031ed2aa4421e20bdb4ba95db2 /src/ini.c
parentc51dff6a4e5bd21491bb0c085cb08f35275332a0 (diff)
downloadimv-4579df9114c00075166b59a67724ec7472facb27.tar.gz
Add support for a basic config file
Diffstat (limited to 'src/ini.c')
-rw-r--r--src/ini.c188
1 files changed, 188 insertions, 0 deletions
diff --git a/src/ini.c b/src/ini.c
new file mode 100644
index 0000000..e4e734d
--- /dev/null
+++ b/src/ini.c
@@ -0,0 +1,188 @@
+#include "ini.h"
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+
+enum parse_state {
+ START,
+ READING_KEY,
+ SEEKING_EQ,
+ SEEKING_VALUE,
+ READING_VALUE,
+ READING_SECTION_KEY,
+ SEEKING_SECTION_VALUE,
+ SEEKING_END_SECTION,
+ READING_SECTION_VALUE,
+ ACCEPT,
+ REJECT
+};
+
+int parse_ini_file(FILE* f, char *out_key, size_t key_size, char *out_value, size_t value_size)
+{
+ char buf[512];
+ while(fgets(&buf[0], sizeof(buf), f)) {
+ int type = parse_ini_str(&buf[0], out_key, key_size, out_value, value_size);
+ if(type != 0) {
+ return type;
+ }
+ }
+ return 0;
+}
+
+int parse_ini_str(const char* str, char *out_key, size_t key_size, char *out_value, size_t value_size)
+{
+ /* ignore comments */
+ if(*str == ';') {
+ out_key[0] = 0;
+ out_value[0] = 0;
+ return INI_UNKNOWN;
+ }
+
+ const char *key_start = 0;
+ size_t key_len = 0;
+ const char *value_start = 0;
+ size_t value_len = 0;
+
+ int type = INI_UNKNOWN;
+ enum parse_state state = START;
+ char quote = 0;
+ char c = 0;
+
+ do {
+ c = *str;
+ switch(state) {
+ case START:
+ if(c == '[') {
+ type = INI_SECTION;
+ state = READING_SECTION_KEY;
+ } else if(c != '=') {
+ type = INI_VALUE;
+ state = READING_KEY;
+ key_start = str;
+ ++key_len;
+ } else {
+ state = REJECT;
+ }
+ break;
+ case READING_KEY:
+ if(isspace(c)) {
+ state = SEEKING_EQ;
+ } else if(c == '=') {
+ state = SEEKING_VALUE;
+ } else {
+ ++key_len;
+ }
+ break;
+ case SEEKING_EQ:
+ if(c == '=') {
+ state = SEEKING_VALUE;
+ } else if(!isspace(c)) {
+ state = REJECT;
+ }
+ break;
+ case SEEKING_VALUE:
+ if(c == '"' || c == '\'') {
+ if(!value_start) {
+ quote = c;
+ state = READING_VALUE;
+ } else {
+ state = REJECT;
+ }
+ } else if(!isspace(c)) {
+ value_start = str;
+ ++value_len;
+ state = READING_VALUE;
+ }
+ break;
+ case READING_VALUE:
+ if(quote == 0 && isspace(c)) {
+ state = ACCEPT;
+ } else if(quote && c == quote) {
+ state = ACCEPT;
+ } else if(c == 0) {
+ state = ACCEPT;
+ } else if(c) {
+ if(!value_start) {
+ value_start = str;
+ }
+ ++value_len;
+ } else {
+ state = REJECT;
+ }
+ break;
+ case READING_SECTION_KEY:
+ if(isspace(c)) {
+ state = SEEKING_SECTION_VALUE;
+ } else if(c == ']') {
+ state = ACCEPT;
+ } else {
+ if(!key_start) {
+ key_start = str;
+ }
+ ++key_len;
+ }
+ break;
+ case SEEKING_SECTION_VALUE:
+ if(c == '"' || c == '\'') {
+ quote = c;
+ state = READING_SECTION_VALUE;
+ } else if(c == ']') {
+ state = ACCEPT;
+ } else if(!isspace(c)) {
+ state = REJECT;
+ }
+ break;
+ case READING_SECTION_VALUE:
+ if(quote == 0 && isspace(c)) {
+ state = SEEKING_END_SECTION;
+ } else if(quote && c == quote) {
+ state = SEEKING_END_SECTION;
+ } else if(c == ']') {
+ state = ACCEPT;
+ } else if(c) {
+ if(!value_start) {
+ value_start = str;
+ }
+ ++value_len;
+ } else {
+ state = REJECT;
+ }
+ break;
+ case SEEKING_END_SECTION:
+ if(c == ']') {
+ state = ACCEPT;
+ } else if(!isspace(c)) {
+ state = REJECT;
+ }
+ break;
+ case ACCEPT:
+ if(c != 0 && !isspace(c)) {
+ state = REJECT;
+ }
+ break;
+ case REJECT:
+ return 0;
+ break;
+ }
+ ++str;
+ } while(c != 0 && state != REJECT);
+
+ if(state == ACCEPT) {
+ if(key_len >= key_size) {
+ key_len = key_size - 1;
+ }
+ if(value_len >= value_size) {
+ value_len = value_size - 1;
+ }
+ memcpy(out_key, key_start, key_len);
+ memcpy(out_value, value_start, value_len);
+ out_key[key_len] = 0;
+ out_value[value_len] = 0;
+ return type;
+ } else {
+ out_key[0] = 0;
+ out_value[0] = 0;
+ }
+
+ return INI_UNKNOWN;
+}