|
- #include <ctype.h>
- #include <stdint.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
-
- #include "ini.h"
- #include "compat.h"
-
-
- static inline int stracmp(const char* zstr,
- const char* lstr, size_t len) {
- int diff = 0;
- while (0 == diff && *zstr && len > 0) {
- --len;
- diff = (*zstr - *lstr);
- ++zstr;
- ++lstr;
- }
- if (0 == diff) {
- if (0 == len && !*zstr) diff = *zstr;
- else if (0 != len && *zstr) diff = *lstr;
- }
- return diff;
- }
-
- static const ini_datum* find_name(const ini_datum* schema,
- const char* name, int len,
- const ini_data_type type) {
- if (0 == stracmp(schema->name, name, len)) {
- return schema;
- }
- for (int i = 0; i < schema->count; ++i) {
- if ( ( ini_none == type ||
- type == schema->data[i].type) &&
- 0 == stracmp(schema->data[i].name, name, len)) {
- return &schema->data[i];
- }
- }
- return NULL;
- }
-
- static inline int needs_quotes(const char* str) {
- while (*str && !isspace(*str) && ',' != *str) ++str;
- return !!(*str);
- }
-
-
- static int _write_ini_file(FILE* file, const ini_datum* schema,
- const void* data, int level) {
- int status = 0;
- const void* ptr = (data + schema->offset);
-
- if (ini_section == schema->type) {
- fprintf(file, "[%s]\n", schema->name);
- for (int i = 0; i < schema->count; ++i) {
- _write_ini_file(file, &schema->data[i],
- ptr, level + 1);
- if (schema->count - 1 != i) fputc('\n', file);
- }
- if (0 != level) fputc('\n', file);
-
- } else if (ini_comment == schema->type) {
- fprintf(file, "; %s", *(char**)ptr);
-
- } else {
- fprintf(file, "%s = ", schema->name);
-
- if (ini_string == schema->type) {
- const char* str = *(char**)ptr;
- if (!needs_quotes(str)) fputs(str, file);
- else fprintf(file, "\"%s\"", str);
-
- } else if (ini_integer == schema->type) {
- fprintf(file, "%d", *(uint32_t*)ptr);
-
- } else if (ini_flag == schema->type) {
- fprintf(file, "%d", !!( *(uint32_t*)ptr &
- (1 << schema->shift)));
- }
- }
-
- return status;
- }
-
- int write_ini_file(FILE* file, const ini_datum* schema,
- const void* data) {
- return _write_ini_file(file, schema, data, 0);
- }
-
- static inline const char* first_char(const char* str) {
- while (*str && isspace(*str)) ++str;
- return str;
- }
-
- static inline const char* first_space(const char* str) {
- while (*str && !isspace(*str)) ++str;
- return str;
- }
-
- static inline const char* end_key(const char* str) {
- while (*str && '=' != *str && !isspace(*str)) ++str;
- return str;
- }
-
- static inline const char* last_char(const char* str) {
- int len = strlen(str);
- const char* end = str + len - 1;
- while (end > str && isspace(*end)) --end;
- return end;
- }
-
- static inline char* parse_string(const char* str) {
- const char* last = last_char(str);
- if ('"' == str[0] && '"' == *last) {
- ++str;
- --last;
- }
- return strndup(str, last - str + 1);
- }
-
- static inline int parse_key_value(const char* key_start,
- const ini_datum* section,
- void* data) {
- const char* key_end = end_key(key_start + 1);
- if (NULL == key_end) return -1;
-
- const ini_datum* def = find_name(section, key_start,
- (key_end - key_start),
- ini_none);
- if (NULL == def || def->type <= ini_section) return -1;
-
- const char* equal = first_char(key_end);
- if (NULL == equal || '=' != *equal) return -1;
-
- const char* val = first_char(equal + 1);
- if (NULL == val) return -1;
-
- const char* ptr = data + def->offset;
- if (ini_string == def->type) {
- *(char**)ptr = parse_string(val);
-
- } else if ( ini_integer == def->type ||
- ini_flag == def->type) {
- int intval = 0;
- if (0 >= sscanf(val, "%d", &intval)) return -1;
- if (ini_integer == def->type) {
- *(int32_t*)ptr = intval;
- } else {
- int32_t mask = (1 << def->shift);
- if (intval) *(uint32_t*)ptr |= mask;
- else *(uint32_t*)ptr &= ~mask;
- }
- }
-
- return 0;
- }
-
- int read_ini_file(FILE* file, const ini_datum* schema,
- void* data) {
- int status = 0;
- const ini_datum* section = NULL;
- const ini_datum* subsection = NULL;
- void* ptr = data;
- char* line = NULL;
- size_t sz_line = 0;
-
- while (0 == status && 0 <= getline(&line, &sz_line, file)) {
- const char* str = first_char(line);
- if ('[' == str[0]) {
- const char* start = &str[1];
- const char* end = strchr(start, ']');
- if (NULL != end) {
- ptr = data;
- int len = (end - start);
- if ('.' == start[0]) {
- if (NULL != section) {
- subsection = find_name(
- section, start, len, ini_section
- );
- ptr += section->offset;
- if (NULL != subsection) {
- ptr += subsection->offset;
- }
- }
- } else {
- section = find_name(
- schema, start, len, ini_section
- );
- subsection = section;
- if (NULL != section) ptr += section->offset;
- }
- }
-
- } else if (';' == str[0]) {
- // Ignore comments
-
- } else if (isalnum(str[0])) {
- // Key-value
- // Ignoring return value:
- // - Unknown sections or keys are ignored
- // - Just ignore malformed files, I guess
- parse_key_value(str, subsection, ptr);
- }
- }
-
- free(line);
-
- return status;
- }
|