summaryrefslogtreecommitdiff
path: root/3rdparty/plibsys/src/pinifile.c
diff options
context:
space:
mode:
authorsanine <sanine.not@pm.me>2022-08-27 23:52:56 -0500
committersanine <sanine.not@pm.me>2022-08-27 23:52:56 -0500
commita4dd0ad63c00f4dee3b86dfd3075d1d61b2b3180 (patch)
tree13bd5bfa15e6fea2a12f176bae79adf9c6fd0933 /3rdparty/plibsys/src/pinifile.c
parentbde3e4f1bb7b8f8abca0884a7d994ee1c17a66b1 (diff)
add plibsys
Diffstat (limited to '3rdparty/plibsys/src/pinifile.c')
-rw-r--r--3rdparty/plibsys/src/pinifile.c503
1 files changed, 503 insertions, 0 deletions
diff --git a/3rdparty/plibsys/src/pinifile.c b/3rdparty/plibsys/src/pinifile.c
new file mode 100644
index 0000000..d8361fc
--- /dev/null
+++ b/3rdparty/plibsys/src/pinifile.c
@@ -0,0 +1,503 @@
+/*
+ * The MIT License
+ *
+ * Copyright (C) 2012-2016 Alexander Saprykin <saprykin.spb@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * 'Software'), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "perror.h"
+#include "pinifile.h"
+#include "plist.h"
+#include "pmem.h"
+#include "pstring.h"
+#include "perror-private.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#define P_INI_FILE_MAX_LINE 1024
+
+typedef struct PIniParameter_ {
+ pchar *name;
+ pchar *value;
+} PIniParameter;
+
+typedef struct PIniSection_ {
+ pchar *name;
+ PList *keys;
+} PIniSection;
+
+struct PIniFile_ {
+ pchar *path;
+ PList *sections;
+ pboolean is_parsed;
+};
+
+static PIniParameter * pp_ini_file_parameter_new (const pchar *name, const pchar *val);
+static void pp_ini_file_parameter_free (PIniParameter *param);
+static PIniSection * pp_ini_file_section_new (const pchar *name);
+static void pp_ini_file_section_free (PIniSection *section);
+static pchar * pp_ini_file_find_parameter (const PIniFile *file, const pchar *section, const pchar *key);
+
+static PIniParameter *
+pp_ini_file_parameter_new (const pchar *name,
+ const pchar *val)
+{
+ PIniParameter *ret;
+
+ if (P_UNLIKELY ((ret = p_malloc0 (sizeof (PIniParameter))) == NULL))
+ return NULL;
+
+ if (P_UNLIKELY ((ret->name = p_strdup (name)) == NULL)) {
+ p_free (ret);
+ return NULL;
+ }
+
+ if (P_UNLIKELY ((ret->value = p_strdup (val)) == NULL)) {
+ p_free (ret->name);
+ p_free (ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+static void
+pp_ini_file_parameter_free (PIniParameter *param)
+{
+ p_free (param->name);
+ p_free (param->value);
+ p_free (param);
+}
+
+static PIniSection *
+pp_ini_file_section_new (const pchar *name)
+{
+ PIniSection *ret;
+
+ if (P_UNLIKELY ((ret = p_malloc0 (sizeof (PIniSection))) == NULL))
+ return NULL;
+
+ if (P_UNLIKELY ((ret->name = p_strdup (name)) == NULL)) {
+ p_free (ret);
+ return NULL;
+ }
+
+ return ret;
+}
+
+static void
+pp_ini_file_section_free (PIniSection *section)
+{
+ p_list_foreach (section->keys, (PFunc) pp_ini_file_parameter_free, NULL);
+ p_list_free (section->keys);
+ p_free (section->name);
+ p_free (section);
+}
+
+static pchar *
+pp_ini_file_find_parameter (const PIniFile *file, const pchar *section, const pchar *key)
+{
+ PList *item;
+
+ if (P_UNLIKELY (file == NULL || file->is_parsed == FALSE || section == NULL || key == NULL))
+ return NULL;
+
+ for (item = file->sections; item != NULL; item = item->next)
+ if (strcmp (((PIniSection *) item->data)->name, section) == 0)
+ break;
+
+ if (item == NULL)
+ return NULL;
+
+ for (item = ((PIniSection *) item->data)->keys; item != NULL; item = item->next)
+ if (strcmp (((PIniParameter *) item->data)->name, key) == 0)
+ return p_strdup (((PIniParameter *) item->data)->value);
+
+ return NULL;
+}
+
+P_LIB_API PIniFile *
+p_ini_file_new (const pchar *path)
+{
+ PIniFile *ret;
+
+ if (P_UNLIKELY (path == NULL))
+ return NULL;
+
+ if (P_UNLIKELY ((ret = p_malloc0 (sizeof (PIniFile))) == NULL))
+ return NULL;
+
+ if (P_UNLIKELY ((ret->path = p_strdup (path)) == NULL)) {
+ p_free (ret);
+ return NULL;
+ }
+
+ ret->is_parsed = FALSE;
+
+ return ret;
+}
+
+P_LIB_API void
+p_ini_file_free (PIniFile *file)
+{
+ if (P_UNLIKELY (file == NULL))
+ return;
+
+ p_list_foreach (file->sections, (PFunc) pp_ini_file_section_free, NULL);
+ p_list_free (file->sections);
+ p_free (file->path);
+ p_free (file);
+}
+
+P_LIB_API pboolean
+p_ini_file_parse (PIniFile *file,
+ PError **error)
+{
+ PIniSection *section;
+ PIniParameter *param;
+ FILE *in_file;
+ pchar *dst_line, *tmp_str;
+ pchar src_line[P_INI_FILE_MAX_LINE + 1],
+ key[P_INI_FILE_MAX_LINE + 1],
+ value[P_INI_FILE_MAX_LINE + 1];
+ pint bom_shift;
+
+ if (P_UNLIKELY (file == NULL)) {
+ p_error_set_error_p (error,
+ (pint) P_ERROR_IO_INVALID_ARGUMENT,
+ 0,
+ "Invalid input argument");
+ return FALSE;
+ }
+
+ if (file->is_parsed)
+ return TRUE;
+
+ if (P_UNLIKELY ((in_file = fopen (file->path, "r")) == NULL)) {
+ p_error_set_error_p (error,
+ (pint) p_error_get_last_io (),
+ p_error_get_last_system (),
+ "Failed to open file for reading");
+ return FALSE;
+ }
+
+ dst_line = NULL;
+ section = NULL;
+ param = NULL;
+
+ memset (src_line, 0, sizeof (src_line));
+
+ while (fgets (src_line, sizeof (src_line), in_file) != NULL) {
+ /* UTF-8, UTF-16 and UTF-32 BOM detection */
+ if ((puchar) src_line[0] == 0xEF && (puchar) src_line[1] == 0xBB && (puchar) src_line[2] == 0xBF)
+ bom_shift = 3;
+ else if (((puchar) src_line[0] == 0xFE && (puchar) src_line[1] == 0xFF) ||
+ ((puchar) src_line[0] == 0xFF && (puchar) src_line[1] == 0xFE))
+ bom_shift = 2;
+ else if ((puchar) src_line[0] == 0x00 && (puchar) src_line[1] == 0x00 &&
+ (puchar) src_line[2] == 0xFE && (puchar) src_line[3] == 0xFF)
+ bom_shift = 4;
+ else if ((puchar) src_line[0] == 0xFF && (puchar) src_line[1] == 0xFE &&
+ (puchar) src_line[2] == 0x00 && (puchar) src_line[3] == 0x00)
+ bom_shift = 4;
+ else
+ bom_shift = 0;
+
+ dst_line = p_strchomp (src_line + bom_shift);
+
+ if (dst_line == NULL)
+ continue;
+
+ /* This should not happen */
+ if (P_UNLIKELY (strlen (dst_line) > P_INI_FILE_MAX_LINE))
+ dst_line[P_INI_FILE_MAX_LINE] = '\0';
+
+ if (dst_line[0] == '[' && dst_line[strlen (dst_line) - 1] == ']' &&
+ sscanf (dst_line, "[%[^]]", key) == 1) {
+ /* New section found */
+ if ((tmp_str = p_strchomp (key)) != NULL) {
+ /* This should not happen */
+ if (P_UNLIKELY (strlen (tmp_str) > P_INI_FILE_MAX_LINE))
+ tmp_str[P_INI_FILE_MAX_LINE] = '\0';
+
+ strcpy (key, tmp_str);
+ p_free (tmp_str);
+
+ if (section != NULL) {
+ if (section->keys == NULL)
+ pp_ini_file_section_free (section);
+ else
+ file->sections = p_list_prepend (file->sections, section);
+ }
+
+ section = pp_ini_file_section_new (key);
+ }
+ } else if (sscanf (dst_line, "%[^=] = \"%[^\"]\"", key, value) == 2 ||
+ sscanf (dst_line, "%[^=] = '%[^\']'", key, value) == 2 ||
+ sscanf (dst_line, "%[^=] = %[^;#]", key, value) == 2) {
+ /* New parameter found */
+ if ((tmp_str = p_strchomp (key)) != NULL) {
+ /* This should not happen */
+ if (P_UNLIKELY (strlen (tmp_str) > P_INI_FILE_MAX_LINE))
+ tmp_str[P_INI_FILE_MAX_LINE] = '\0';
+
+ strcpy (key, tmp_str);
+ p_free (tmp_str);
+
+ if ((tmp_str = p_strchomp (value)) != NULL) {
+ /* This should not happen */
+ if (P_UNLIKELY (strlen (tmp_str) > P_INI_FILE_MAX_LINE))
+ tmp_str[P_INI_FILE_MAX_LINE] = '\0';
+
+ strcpy (value, tmp_str);
+ p_free (tmp_str);
+
+ if (strcmp (value, "\"\"") == 0 || (strcmp (value, "''") == 0))
+ value[0] = '\0';
+
+ if (section != NULL && (param = pp_ini_file_parameter_new (key, value)) != NULL)
+ section->keys = p_list_prepend (section->keys, param);
+ }
+ }
+ }
+
+ p_free (dst_line);
+ memset (src_line, 0, sizeof (src_line));
+ }
+
+ if (section != NULL) {
+ if (section->keys == NULL)
+ pp_ini_file_section_free (section);
+ else
+ file->sections = p_list_append (file->sections, section);
+ }
+
+ if (P_UNLIKELY (fclose (in_file) != 0))
+ P_WARNING ("PIniFile::p_ini_file_parse: fclose() failed");
+
+ file->is_parsed = TRUE;
+
+ return TRUE;
+}
+
+P_LIB_API pboolean
+p_ini_file_is_parsed (const PIniFile *file)
+{
+ if (P_UNLIKELY (file == NULL))
+ return FALSE;
+
+ return file->is_parsed;
+}
+
+P_LIB_API PList *
+p_ini_file_sections (const PIniFile *file)
+{
+ PList *ret;
+ PList *sec;
+
+ if (P_UNLIKELY (file == NULL || file->is_parsed == FALSE))
+ return NULL;
+
+ ret = NULL;
+
+ for (sec = file->sections; sec != NULL; sec = sec->next)
+ ret = p_list_prepend (ret, p_strdup (((PIniSection *) sec->data)->name));
+
+ return ret;
+}
+
+P_LIB_API PList *
+p_ini_file_keys (const PIniFile *file,
+ const pchar *section)
+{
+ PList *ret;
+ PList *item;
+
+ if (P_UNLIKELY (file == NULL || file->is_parsed == FALSE || section == NULL))
+ return NULL;
+
+ ret = NULL;
+
+ for (item = file->sections; item != NULL; item = item->next)
+ if (strcmp (((PIniSection *) item->data)->name, section) == 0)
+ break;
+
+ if (item == NULL)
+ return NULL;
+
+ for (item = ((PIniSection *) item->data)->keys; item != NULL; item = item->next)
+ ret = p_list_prepend (ret, p_strdup (((PIniParameter *) item->data)->name));
+
+ return ret;
+}
+
+P_LIB_API pboolean
+p_ini_file_is_key_exists (const PIniFile *file,
+ const pchar *section,
+ const pchar *key)
+{
+ PList *item;
+
+ if (P_UNLIKELY (file == NULL || file->is_parsed == FALSE || section == NULL || key == NULL))
+ return FALSE;
+
+ for (item = file->sections; item != NULL; item = item->next)
+ if (strcmp (((PIniSection *) item->data)->name, section) == 0)
+ break;
+
+ if (item == NULL)
+ return FALSE;
+
+ for (item = ((PIniSection *) item->data)->keys; item != NULL; item = item->next)
+ if (strcmp (((PIniParameter *) item->data)->name, key) == 0)
+ return TRUE;
+
+ return FALSE;
+}
+
+P_LIB_API pchar *
+p_ini_file_parameter_string (const PIniFile *file,
+ const pchar *section,
+ const pchar *key,
+ const pchar *default_val)
+{
+ pchar *val;
+
+ if ((val = pp_ini_file_find_parameter (file, section, key)) == NULL)
+ return p_strdup (default_val);
+
+ return val;
+}
+
+P_LIB_API pint
+p_ini_file_parameter_int (const PIniFile *file,
+ const pchar *section,
+ const pchar *key,
+ pint default_val)
+{
+ pchar *val;
+ pint ret;
+
+ if ((val = pp_ini_file_find_parameter (file, section, key)) == NULL)
+ return default_val;
+
+ ret = atoi (val);
+ p_free (val);
+
+ return ret;
+}
+
+P_LIB_API double
+p_ini_file_parameter_double (const PIniFile *file,
+ const pchar *section,
+ const pchar *key,
+ double default_val)
+{
+ pchar *val;
+ pdouble ret;
+
+ if ((val = pp_ini_file_find_parameter (file, section, key)) == NULL)
+ return default_val;
+
+ ret = p_strtod (val);
+ p_free (val);
+
+ return ret;
+}
+
+P_LIB_API pboolean
+p_ini_file_parameter_boolean (const PIniFile *file,
+ const pchar *section,
+ const pchar *key,
+ pboolean default_val)
+{
+ pchar *val;
+ pboolean ret;
+
+ if ((val = pp_ini_file_find_parameter (file, section, key)) == NULL)
+ return default_val;
+
+ if (strcmp (val, "true") == 0 || strcmp (val, "TRUE") == 0)
+ ret = TRUE;
+ else if (strcmp (val, "false") == 0 || strcmp (val, "FALSE") == 0)
+ ret = FALSE;
+ else if (atoi (val) > 0)
+ ret = TRUE;
+ else
+ ret = FALSE;
+
+ p_free (val);
+
+ return ret;
+}
+
+P_LIB_API PList *
+p_ini_file_parameter_list (const PIniFile *file,
+ const pchar *section,
+ const pchar *key)
+{
+ PList *ret = NULL;
+ pchar *val, *str;
+ pchar buf[P_INI_FILE_MAX_LINE + 1];
+ psize len, buf_cnt;
+
+ if ((val = pp_ini_file_find_parameter (file, section, key)) == NULL)
+ return NULL;
+
+ len = strlen (val);
+
+ if (len < 3 || val[0] != '{' || val[len - 1] != '}') {
+ p_free (val);
+ return NULL;
+ }
+
+ /* Skip first brace '{' symbol */
+ str = val + 1;
+ buf[0] = '\0';
+ buf_cnt = 0;
+
+ while (*str && *str != '}') {
+ if (!isspace (* ((const puchar *) str)))
+ buf[buf_cnt++] = *str;
+ else {
+ buf[buf_cnt] = '\0';
+
+ if (buf_cnt > 0)
+ ret = p_list_append (ret, p_strdup (buf));
+
+ buf_cnt = 0;
+ }
+
+ ++str;
+ }
+
+ if (buf_cnt > 0) {
+ buf[buf_cnt] = '\0';
+ ret = p_list_append (ret, p_strdup (buf));
+ }
+
+ p_free (val);
+
+ return ret;
+}