227 lines
5.6 KiB
C
227 lines
5.6 KiB
C
/* Reflow Oven Controller
|
|
*
|
|
* Copyright (C) 2020 Mario Hüttel <mario.huettel@gmx.net>
|
|
*
|
|
* This file is part of the Reflow Oven Controller Project.
|
|
*
|
|
* The reflow oven controller is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* The Reflow Oven Control Firmware 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 the reflow oven controller project.
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/**
|
|
* @addtogroup config-parser
|
|
* @{
|
|
*/
|
|
|
|
#include <config-parser/config-parser.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
|
|
/**
|
|
* @brief Config parser magic value used to check sanity of passed structs
|
|
*/
|
|
#define CONFIG_PARSER_MAGIC 0x464a6e2bUL
|
|
|
|
/**
|
|
* @brief Config parser type casting macro
|
|
*/
|
|
#define CONFIG_PARSER(p) ((struct config_parser *)(p))
|
|
|
|
/**
|
|
* @brief Check if the supplied pointer is a valid @ref config_parser_handle_t
|
|
*
|
|
* If the pointer is invalid, the function using this macro will return with
|
|
* CONFIG_PARSER_PARAM_ERR
|
|
*/
|
|
#define config_parser_check_handle(handle) do { \
|
|
if (!(handle) || \
|
|
((struct config_parser *)(handle))->magic != CONFIG_PARSER_MAGIC) \
|
|
return CONFIG_PARSER_PARAM_ERR; \
|
|
} while (0)
|
|
|
|
config_parser_handle_t config_parser_open_file(struct config_parser *config_parser, bool write, const char *file_name,
|
|
char *working_buffer, size_t buff_size)
|
|
{
|
|
FRESULT res;
|
|
|
|
if (!config_parser || !file_name || !working_buffer)
|
|
return NULL;
|
|
|
|
config_parser->magic = CONFIG_PARSER_MAGIC;
|
|
config_parser->write = write;
|
|
config_parser->buffer = working_buffer;
|
|
config_parser->buff_size = buff_size;
|
|
|
|
res = f_open(&config_parser->file, file_name, (write ? FA_CREATE_ALWAYS | FA_WRITE : FA_READ));
|
|
if (res != FR_OK)
|
|
return NULL;
|
|
|
|
return (config_parser_handle_t)config_parser;
|
|
}
|
|
|
|
/**
|
|
* @brief Token delimiters for the config parser.
|
|
*/
|
|
static const char * const token_delim = " \t";
|
|
|
|
/**
|
|
* @brief Parse a value in the configuration
|
|
* @param entry Entry to parse the value in to
|
|
* @param value_start_token char pointer holding the value. Must be null-terminated
|
|
* @return 0 if successful
|
|
*/
|
|
static int parse_value(struct config_parser_entry *entry, char *value_start_token)
|
|
{
|
|
char *dot;
|
|
char *endptr;
|
|
|
|
/* Check if token is a float number */
|
|
dot = strstr(value_start_token, ".");
|
|
if (dot) {
|
|
/* Try parsing as float */
|
|
entry->value.float_val = strtof(value_start_token, &endptr);
|
|
if (endptr == value_start_token)
|
|
return -1;
|
|
entry->type = CONFIG_PARSER_TYPE_FLOAT;
|
|
goto exit;
|
|
}
|
|
|
|
if (value_start_token[0] != '-') {
|
|
/* Try parsing as ul */
|
|
entry->value.uint_val = strtoul(value_start_token, &endptr, 0);
|
|
if (endptr == value_start_token)
|
|
return -1;
|
|
|
|
entry->type = CONFIG_PARSER_TYPE_UINT;
|
|
goto exit;
|
|
} else {
|
|
/* Try parsing as int */
|
|
entry->value.int_val = strtod(value_start_token, &endptr);
|
|
if (endptr == value_start_token)
|
|
return -1;
|
|
|
|
entry->type = CONFIG_PARSER_TYPE_INT;
|
|
}
|
|
|
|
exit:
|
|
return 0;
|
|
}
|
|
|
|
enum config_parser_ret config_parser_get_line(config_parser_handle_t handle, struct config_parser_entry *entry,
|
|
bool force_float)
|
|
{
|
|
struct config_parser *p;
|
|
char *token;
|
|
int token_round = 0;
|
|
|
|
config_parser_check_handle(handle);
|
|
p = CONFIG_PARSER(handle);
|
|
|
|
if (!entry)
|
|
return CONFIG_PARSER_PARAM_ERR;
|
|
|
|
p->buffer[0] = '\0';
|
|
if (f_gets(p->buffer, (int)p->buff_size, &p->file) == NULL)
|
|
return CONFIG_PARSER_IOERR;
|
|
|
|
token = strtok(p->buffer, token_delim);
|
|
while (token != NULL) {
|
|
/* Check for comment */
|
|
if (token[0] == '#') {
|
|
if (token_round == 0)
|
|
return CONFIG_PARSER_LINE_COMMENT;
|
|
break;
|
|
}
|
|
|
|
switch (token_round) {
|
|
case 0: /* KEY */
|
|
entry->name = token;
|
|
break;
|
|
case 1: /* = Symbol */
|
|
if (strcmp(token, "="))
|
|
return CONFIG_PARSER_LINE_MALFORM;
|
|
break;
|
|
case 2: /* VALUE */
|
|
if (parse_value(entry, token))
|
|
return CONFIG_PARSER_LINE_MALFORM;
|
|
break;
|
|
default:
|
|
return CONFIG_PARSER_LINE_MALFORM;
|
|
}
|
|
|
|
token_round++;
|
|
token = strtok(NULL, token_delim);
|
|
}
|
|
|
|
if (force_float) {
|
|
if (entry->type == CONFIG_PARSER_TYPE_INT)
|
|
entry->value.float_val = (float)entry->value.int_val;
|
|
if (entry->type == CONFIG_PARSER_TYPE_UINT)
|
|
entry->value.float_val = (float)entry->value.uint_val;
|
|
|
|
entry->type = CONFIG_PARSER_TYPE_FLOAT;
|
|
}
|
|
|
|
return CONFIG_PARSER_OK;
|
|
}
|
|
|
|
enum config_parser_ret config_parser_reset_to_start(config_parser_handle_t handle)
|
|
{
|
|
FRESULT res;
|
|
struct config_parser *p;
|
|
|
|
config_parser_check_handle(handle);
|
|
p = CONFIG_PARSER(handle);
|
|
|
|
res = f_rewind(&p->file);
|
|
if (res != FR_OK)
|
|
return CONFIG_PARSER_IOERR;
|
|
|
|
return CONFIG_PARSER_OK;
|
|
}
|
|
|
|
enum config_parser_ret config_parser_write_entry(config_parser_handle_t handle, const struct config_parser_entry *entry)
|
|
{
|
|
(void)entry;
|
|
config_parser_check_handle(handle);
|
|
|
|
return CONFIG_PARSER_OK;
|
|
}
|
|
|
|
enum config_parser_ret config_parser_close_file(config_parser_handle_t handle)
|
|
{
|
|
struct config_parser *p;
|
|
FRESULT res;
|
|
|
|
config_parser_check_handle(handle);
|
|
p = CONFIG_PARSER(handle);
|
|
|
|
res = f_close(&p->file);
|
|
|
|
return (res == FR_OK ? CONFIG_PARSER_OK : CONFIG_PARSER_IOERR);
|
|
}
|
|
|
|
bool config_parser_ret_is_abort_condition(enum config_parser_ret return_val)
|
|
{
|
|
if (return_val == CONFIG_PARSER_END_REACHED ||
|
|
return_val == CONFIG_PARSER_GENERIC_ERR ||
|
|
return_val == CONFIG_PARSER_IOERR ||
|
|
return_val == CONFIG_PARSER_PARAM_ERR)
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
/** @} */
|