187 lines
5.8 KiB
C
187 lines
5.8 KiB
C
/*
|
|
* microconf.h
|
|
*
|
|
* Copyright 2025
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
|
* MA 02110-1301, USA.
|
|
*
|
|
*
|
|
*/
|
|
|
|
|
|
#if (!defined(__LIB_MICROCONF_PARSER))
|
|
#define __LIB_MICROCONF_PARSER
|
|
|
|
#define bool char
|
|
#define true 1
|
|
#define is_space_test(x) (x <= 32 && x >= 0)
|
|
#define false 0
|
|
#define ulong unsigned long
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
typedef FILE* file_t;
|
|
typedef struct {
|
|
size_t max_len_key;
|
|
size_t max_len_val;
|
|
ulong max_cnt;
|
|
} config_info_t;
|
|
typedef struct {
|
|
char* key;
|
|
char* value;
|
|
} save_data_t;
|
|
|
|
void _remove_spaces_end(char* str) {
|
|
if (str != NULL) {
|
|
long pos = strlen(str);
|
|
if (pos == 0) return;
|
|
pos --;
|
|
while (pos != 0) {
|
|
if (is_space_test(str[pos])) str[pos] = '\0';
|
|
else {
|
|
if (str[pos + 1] != '\0') str[pos + 1] = '\0';
|
|
return;
|
|
}
|
|
pos --;
|
|
}
|
|
}
|
|
}
|
|
|
|
int _microconf_read_file(file_t fp, save_data_t (*input_handler) (ulong), size_t max_len, size_t max_len_val, ulong max_cnt) {
|
|
|
|
int c;
|
|
bool is_comment = false;
|
|
bool is_space = true;
|
|
bool read_key = false;
|
|
bool read_val = false;
|
|
bool read_val_spaces = true;
|
|
bool print_warning = true;
|
|
ulong num = 0;
|
|
size_t key_addr = 0;
|
|
size_t val_addr = 0;
|
|
save_data_t sv = {NULL, NULL};
|
|
int old = '\0';
|
|
ulong str_num = 0;
|
|
|
|
while ((c = getc(fp)) != EOF) {
|
|
/* Разделитель - перенос строки ('\n') */
|
|
if (c == '\n') {
|
|
is_comment = false;
|
|
is_space = true;
|
|
read_key = false;
|
|
read_val = false;
|
|
key_addr = 0;
|
|
val_addr = 0;
|
|
read_val_spaces = true;
|
|
print_warning = true;
|
|
str_num ++;
|
|
}
|
|
/* Считать комментарием все до конца строки */
|
|
if (c == '#') is_comment = true;
|
|
/* Если символ не входит в комментарий, то: */
|
|
if (!is_comment) {
|
|
/* Пропустить пробелы в начале и конце строки */
|
|
if (is_space && !is_space_test(c)) {
|
|
is_space = false;
|
|
read_key = true;
|
|
if (num == max_cnt) {
|
|
puts("\033[1mmicroconf: \033[91mError: The memory is full!\033[0m Code: READ_COUNT_ERR");
|
|
return EXIT_FAILURE;
|
|
}
|
|
_remove_spaces_end(sv.key);
|
|
_remove_spaces_end(sv.value);
|
|
sv = input_handler(num);
|
|
num ++;
|
|
key_addr = 0;
|
|
val_addr = 0;
|
|
}
|
|
}
|
|
/* Чтение значения */
|
|
if (read_val) {
|
|
if (read_val_spaces && !is_space_test(c)) read_val_spaces = false;
|
|
if (!read_val_spaces) {
|
|
if (c == '\n' || c == '#' || c == EOF) {
|
|
val_addr --;
|
|
sv.value[val_addr] = '\0';
|
|
read_val = false;
|
|
}
|
|
if (read_val) {
|
|
if (sv.value != NULL) {
|
|
sv.value[val_addr] = c;
|
|
}
|
|
val_addr ++;
|
|
if (val_addr >= max_len_val && print_warning) {
|
|
puts("\033[1mmicroconf: \033[35mWarning: The memory is full!\033[0m Code: READ_VAL_ERR");
|
|
val_addr --;
|
|
print_warning = false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/* Чтение ключа */
|
|
if (read_key) {
|
|
if (c == ':' && old == ':') {
|
|
key_addr --;
|
|
sv.key[key_addr] = '\0';
|
|
read_key = false;
|
|
read_val = true;
|
|
val_addr = 0;
|
|
}
|
|
if (read_key) {
|
|
if (sv.key != NULL) {
|
|
sv.key[key_addr] = c;
|
|
}
|
|
key_addr ++;
|
|
if (key_addr >= max_len && print_warning) {
|
|
puts("\033[1mmicroconf: \033[35mWarning: The memory is full!\033[0m Code: READ_KEY_ERR");
|
|
key_addr --;
|
|
print_warning = false;
|
|
}
|
|
}
|
|
}
|
|
/* Проверка синтаксиса файла */
|
|
if ((c == '\n' || c == '#' || c == EOF) && read_key) {
|
|
printf("\033[1mmicroconf: \033[91mError: Syntax error on line %lu\033[0m\n", str_num);
|
|
return EXIT_FAILURE;
|
|
}
|
|
/* Сохраняем старое значение в переменную */
|
|
old = c;
|
|
}
|
|
/* Удаляем пробелы в конце строки */
|
|
_remove_spaces_end(sv.key);
|
|
_remove_spaces_end(sv.value);
|
|
return EXIT_SUCCESS;
|
|
}
|
|
|
|
int microconf_compile(file_t fp, save_data_t (*input_handler) (ulong), config_info_t st) {
|
|
if (fp == NULL) {
|
|
puts("\033[1mmicroconf: \033[91mError: Unable to open file!\033[0m");
|
|
return EXIT_FAILURE;
|
|
}
|
|
rewind(fp);
|
|
return _microconf_read_file(fp, input_handler, st.max_len_key, st.max_len_val, st.max_cnt);
|
|
}
|
|
|
|
#undef bool
|
|
#undef ulong
|
|
#undef true
|
|
#undef false
|
|
#undef is_space_test
|
|
|
|
#endif
|