commit 0a001d30181bf6eacfba9d43a3e9995ae0bf6eb8
parent 0de89e7f815217e06c413552a445c3ddeb8d6526
Author: Remy Noulin <loader2x@gmail.com>
Date: Sat, 19 May 2018 23:58:14 +0200
ini parser package
example/ini.conf | 16 +++++
example/main.c | 37 ++++++++++
package.yml | 18 +++++
src/.gdb_history | 14 ++++
src/ini.c | 204 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/ini.h | 22 ++++++
6 files changed, 311 insertions(+)
Diffstat:
6 files changed, 311 insertions(+), 0 deletions(-)
diff --git a/example/ini.conf b/example/ini.conf
@@ -0,0 +1,16 @@
+project = ini
+version = 0.1.0
+ test = no
+#ignore
+[config]
+name = "Michael Lazear"
+date = 12/9/1873
+#[data]
+town = Margaritaville
+age = NaN
+[output]
+format=utf-8
+language=english
+long="This string
+spans multiple
+lines"
diff --git a/example/main.c b/example/main.c
@@ -0,0 +1,37 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include "../src/ini.h"
+#include "libsheepyObject.h"
+
+int callback(char* section, char* config, char* value)
+{
+ printf("[%s] \"%s\" == \"%s\"\n", section, config, value);
+ return 0;
+}
+
+int main(int argc, char** argv) {
+ if (argc < 2) {
+ printf("usage: %s file ...\noutput ini configuration values\n", argv[0]);
+ return EXIT_FAILURE;
+ }
+
+ smallDictt *ini = parseIni(argv[1]);
+ //logVarG(ini);
+ createAllocateSmallJson(js);
+ setTopG(js, (baset*) ini);
+ logNFree(stringifyG(js,2));
+ XSUCCESS
+
+ int i;
+ for (i = 1; i < argc; i++) {
+ printf("parsing %s\n", argv[i]);
+ FILE* fp = fopen(argv[i], "r");
+ if (! fp) {
+ fprintf(stderr, "Error opening %s\n", argv[i]);
+ return EXIT_FAILURE;
+ }
+ ini_parse_file(fp, callback);
+ fclose(fp);
+ }
+ return EXIT_SUCCESS;
+}
diff --git a/package.yml b/package.yml
@@ -0,0 +1,18 @@
+---
+ name: ini
+ version: 0.0.4
+ description: An ini configuration file parser
+ bin: ./src/ini.c
+ scripts:
+ test: echo "Error no test specified" && exit 1
+ repository:
+ type: git
+ url: git+https://github.com/RemyNoulin/ini.git
+ keywords:
+ - utility
+ - command
+ author: Remy Noulin
+ license: MIT
+ bugs:
+ url: https://github.com/RemyNoulin/ini/issues
+ homepage: https://github.com/RemyNoulin/ini
diff --git a/src/.gdb_history b/src/.gdb_history
@@ -0,0 +1,14 @@
+b main
+r
+n
+p mainFilename
+n
+b 311
+c
+n
+n
+record
+b 311
+r
+n
+c
diff --git a/src/ini.c b/src/ini.c
@@ -0,0 +1,204 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include "ini.h"
+
+internal int read_until(FILE* fp, char* buffer, int size, int delim);
+
+internal int callback(char* section, char* config, char* value, smallDictt *r)
+{
+ //printf("[%s] \"%s\" == \"%s\"\n", section, config, value);
+ if (isBlankG(section)) {
+ setG(r, config, value);
+ }
+ else {
+ smallDictt *sect = getG(r, rtSmallDictt, section);
+ if (sect) {
+ setG(sect, config, value);
+ setPG(r, section, sect);
+ }
+ else {
+ sect = allocG(rtSmallDictt);
+ setG(sect, config, value);
+ setNFreeG(r, section, sect);
+ }
+ }
+ return 0;
+}
+
+/**
+ * @brief Parse an ini file.
+ * @details Parse an ini file. Passes values to a callback function.
+ * No dynamic memory is allocated.
+ *
+ * @param fp Open file pointer to read INI file from
+ * @param callback Callback function accepting three arguments:
+ * section, variable, and value strings.
+ * @return 0 on success, error code on failure
+ */
+internal int iniParseFile(FILE* fp, int (*callback)(char*, char*, char*, smallDictt *), smallDictt *r)
+{
+ if ((fp == NULL) || (callback == NULL))
+ return -1;
+
+ char section [BUFFER_SIZE] = "";
+ char config [BUFFER_SIZE] = "";
+ char value [BUFFER_SIZE] = "";
+ int c;
+ int err;
+ while((c = getc(fp)) != EOF) {
+ switch(c) {
+ case '#': {
+ while ((c = getc(fp)) != '\n')
+ ;
+ break;
+ }
+ case '[': {
+ err = read_until(fp, section, BUFFER_SIZE, ']');
+ if (err)
+ return err;
+ break;
+ }
+ case '=': {
+ err = read_until(fp, value, BUFFER_SIZE, '\n');
+ if (err)
+ return err;
+ err = callback(section, config, value, r);
+ if (err)
+ return err;
+ break;
+ }
+ case '\n': case ' ': case '\t':
+ break;
+ default:
+ ungetc(c, fp);
+ err = read_until(fp, config, BUFFER_SIZE, '=');
+ if (err)
+ return err;
+ break;
+ }
+ }
+ return -1;
+}
+
+smallDictt *parseIni(const char *filename)
+{
+ FILE* fp = fopen(filename, "r");
+ pTestErrorCmd(fp == NULL, return NULL);
+
+ createAllocateSmallDict(r);
+ iniParseFile(fp, callback, r);
+ fclose(fp);
+ return r;
+}
+
+internal int read_until(FILE* fp, char* buffer, int size, int delim)
+{
+ char c;
+ int i = 0;
+ memset(buffer, 0, size);
+ int string = 0;
+ while (i < size) {
+ c = getc(fp);
+ if(isblank(c) && string == 0) {
+ continue;
+ } else if (c == '\"') {
+ string = 1;
+ } else if (c == delim) {
+ buffer[i] = '\0';
+ if (delim == '=')
+ ungetc(c, fp);
+ return 0;
+ } else if (c == EOF) {
+ return 0;
+ }
+ buffer[i++] = c;
+ }
+ buffer[i] = '\0';
+ return -1;
+}
+
+/**
+ * @brief Parse an ini file.
+ * @details Parse an ini file. Passes values to a callback function.
+ * No dynamic memory is allocated.
+ *
+ * @param fp Open file pointer to read INI file from
+ * @param callback Callback function accepting three arguments:
+ * section, variable, and value strings.
+ * @return 0 on success, error code on failure
+ */
+int ini_parse_file(FILE* fp, int (*callback)(char*, char*, char*))
+{
+ if ((fp == NULL) || (callback == NULL))
+ return -1;
+
+ char section [BUFFER_SIZE] = "";
+ char config [BUFFER_SIZE] = "";
+ char value [BUFFER_SIZE] = "";
+ int c;
+ int err;
+ while((c = getc(fp)) != EOF) {
+ switch(c) {
+ case '#': {
+ while ((c = getc(fp)) != '\n')
+ ;
+ break;
+ }
+ case '[': {
+ err = read_until(fp, section, BUFFER_SIZE, ']');
+ if (err)
+ return err;
+ break;
+ }
+ case '=': {
+ err = read_until(fp, value, BUFFER_SIZE, '\n');
+ if (err)
+ return err;
+ err = callback(section, config, value);
+ if (err)
+ return err;
+ break;
+ }
+ case '\n': case ' ': case '\t':
+ break;
+ default:
+ ungetc(c, fp);
+ err = read_until(fp, config, BUFFER_SIZE, '=');
+ if (err)
+ return err;
+ break;
+ }
+ }
+ return -1;
+}
+
+bool saveIni(smallDictt *ini, const char *path) {
+ if (!ini || !path) {
+ return false;
+ }
+ createAllocateSmallArray(r);
+ forEachSmallDict(ini, k, D) {
+ cast(smallDictt*, d, D);
+ pushNFreeG(r, catS("[", k, "]"));
+ {forEachSmallDict(d, k2, S) {
+ castS(s, S);
+ if (isBlankG(s)) {
+ pushNFreeG(r, catS(k2, " ="));
+ }
+ else {
+ pushNFreeG(r, catS(k2, " = ", ssGet(s)));
+ }
+ finishG(s);
+ }
+ listFreeS(libsheepyInternalKeys);
+ }
+ pushG(r, "");
+ finishG(d);
+ }
+ listFreeS(libsheepyInternalKeys);
+ writeFileG(r, path);
+ return true;
+}
+
diff --git a/src/ini.h b/src/ini.h
@@ -0,0 +1,22 @@
+#ifndef _INI_H_
+#define _INI_H_
+
+#include "libsheepyObject.h"
+
+#define BUFFER_SIZE 16384
+
+/**
+ * @brief Parse an ini file.
+ * @details Parse an ini file. Passes values to a callback function.
+ * No dynamic memory is allocated.
+ *
+ * @param fp Open file pointer to read INI file from
+ * @param callback Callback function accepting three arguments:
+ * section, variable, and value strings.
+ * @return 0 on success, error code on failure
+ */
+int ini_parse_file(FILE* fp, int (*callback)(char* section, char* variable, char* value));
+
+smallDictt *parseIni(const char *filename);
+bool saveIni(smallDictt *ini, const char *path);
+#endif