1434 lines
61 KiB
C
1434 lines
61 KiB
C
#include "arc/std/config.h"
|
|
|
|
#include "arc/std/array.h"
|
|
#include "arc/std/bool.h"
|
|
#include "arc/std/errno.h"
|
|
#include "arc/std/hashtable.h"
|
|
#include "arc/std/parser.h"
|
|
#include "arc/std/vector.h"
|
|
#include "arc/std/parser/helpers.h"
|
|
#include "arc/std/vector/inline.h"
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
struct ARC_Config {
|
|
ARC_Parser *parser;
|
|
|
|
ARC_Hashtable *types;
|
|
|
|
ARC_Hashtable *groups;
|
|
ARC_Hashtable *currentGroup;
|
|
|
|
ARC_Bool load;
|
|
};
|
|
|
|
typedef struct ARC_ConfigTypeData {
|
|
ARC_Config *config;
|
|
void *data;
|
|
ARC_ConfigType_DestroyFn destroyFn;
|
|
} ARC_ConfigTypeData;
|
|
|
|
void ARC_Config_InitLexerRulesFn(ARC_Lexer *lexer){
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_TAB , '\t'));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_NEWLINE, '\n'));
|
|
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_SPACE , ' ' ));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_BANG , '!' ));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_QUOTE , '"' ));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_HASH , '#' ));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_DOLLAR , '$' ));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_PERCENT , '%' ));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_AMPERSAND , '&' ));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_SINGLE_QUOTE, '\''));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_OPEN_PAREN , '(' ));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_CLOSE_PAREN , ')' ));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_ASTERISK , '*' ));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_PLUS , '+' ));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_COMMA , ',' ));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_MINUS , '-' ));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_PERIOD , '.' ));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_SLASH , '/' ));
|
|
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharOrBetween(ARC_CONFIG_NUMBER , '0', '9'));
|
|
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_COLON , ':'));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_SEMICOLON , ';'));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_LESS_THAN , '<'));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_GREATER_THAN , '>'));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_EQUAL , '='));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_QUESTION_MARK, '?'));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_AT , '@'));
|
|
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharOrBetween(ARC_CONFIG_ALPHA_UPPER_CHAR, 'A', 'Z'));
|
|
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_OPEN_BRACKET , '[' ));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_BACKSLASH , '\\'));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_CLOSE_BRACKET, ']' ));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_CARET , '^' ));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_UNDERSCORE , '_' ));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_GRAVE , '`' ));
|
|
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharOrBetween(ARC_CONFIG_ALPHA_LOWER_CHAR, 'a', 'z'));
|
|
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_OPEN_CURLY_BRACE , '{'));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_VERTICAL_LINE , '|'));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_CLOSE_CURLY_BRACE, '}'));
|
|
ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CONFIG_TILDE , '~'));
|
|
}
|
|
|
|
uint32_t ARC_Config_GetStringIdFn(ARC_String *string){
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "LAMBDA")){
|
|
return ARC_PARSER_TAG_LAMBDA;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "TAB")){
|
|
return ARC_CONFIG_TAB;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "NEWLINE")){
|
|
return ARC_CONFIG_NEWLINE;
|
|
}
|
|
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "SPACE")){
|
|
return ARC_CONFIG_SPACE;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "BANG")){
|
|
return ARC_CONFIG_BANG;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "QUOTE")){
|
|
return ARC_CONFIG_QUOTE;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "HASH")){
|
|
return ARC_CONFIG_HASH;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "DOLLAR")){
|
|
return ARC_CONFIG_DOLLAR;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "PERCENT")){
|
|
return ARC_CONFIG_PERCENT;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "AMPERSAND")){
|
|
return ARC_CONFIG_AMPERSAND;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "SINGLE_QUOTE")){
|
|
return ARC_CONFIG_SINGLE_QUOTE;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "OPEN_PAREN")){
|
|
return ARC_CONFIG_OPEN_PAREN;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "CLOSE_PAREN")){
|
|
return ARC_CONFIG_CLOSE_PAREN;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "ASTERISK")){
|
|
return ARC_CONFIG_ASTERISK;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "PLUS")){
|
|
return ARC_CONFIG_PLUS;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "COMMA")){
|
|
return ARC_CONFIG_COMMA;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "MINUS")){
|
|
return ARC_CONFIG_MINUS;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "PERIOD")){
|
|
return ARC_CONFIG_PERIOD;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "SLASH")){
|
|
return ARC_CONFIG_SLASH;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "NUMBER")){
|
|
return ARC_CONFIG_NUMBER;
|
|
}
|
|
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "COLON")){
|
|
return ARC_CONFIG_COLON;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "SEMICOLON")){
|
|
return ARC_CONFIG_SEMICOLON;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "LESS_THAN")){
|
|
return ARC_CONFIG_LESS_THAN;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "GREATER_THAN")){
|
|
return ARC_CONFIG_GREATER_THAN;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "EQUAL")){
|
|
return ARC_CONFIG_EQUAL;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "QUESTION_MARK")){
|
|
return ARC_CONFIG_QUESTION_MARK;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "AT")){
|
|
return ARC_CONFIG_AT;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "ALPHA_UPPER_CHAR")){
|
|
return ARC_CONFIG_ALPHA_UPPER_CHAR;
|
|
}
|
|
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "OPEN_BRACKET")){
|
|
return ARC_CONFIG_OPEN_BRACKET;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "BACKSLASH")){
|
|
return ARC_CONFIG_BACKSLASH;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "CLOSE_BRACKET")){
|
|
return ARC_CONFIG_CLOSE_BRACKET;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "CARET")){
|
|
return ARC_CONFIG_CARET;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "UNDERSCORE")){
|
|
return ARC_CONFIG_UNDERSCORE;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "GRAVE")){
|
|
return ARC_CONFIG_GRAVE;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "ALPHA_LOWER_CHAR")){
|
|
return ARC_CONFIG_ALPHA_LOWER_CHAR;
|
|
}
|
|
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "OPEN_CURLY_BRACE")){
|
|
return ARC_CONFIG_OPEN_CURLY_BRACE;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "VERTICAL_LINE")){
|
|
return ARC_CONFIG_VERTICAL_LINE;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "CLOSE_CURLY_BRACE")){
|
|
return ARC_CONFIG_CLOSE_CURLY_BRACE;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "TILDE")){
|
|
return ARC_CONFIG_TILDE;
|
|
}
|
|
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<language>")){
|
|
return ARC_CONFIG_LANGUAGE;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<group>")){
|
|
return ARC_CONFIG_GROUP;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<groupName>")){
|
|
return ARC_CONFIG_GROUP_NAME;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<groupArgs>")){
|
|
return ARC_CONFIG_GROUP_ARGS;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<variableLines>")){
|
|
return ARC_CONFIG_VARIABLE_LINES;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<variableLine>")){
|
|
return ARC_CONFIG_VARIABLE_LINE;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<allowSpace>")){
|
|
return ARC_CONFIG_ALLOW_SPACE;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<type>")){
|
|
return ARC_CONFIG_TYPE;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<value>")){
|
|
return ARC_CONFIG_VALUE;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<nestedValue>")){
|
|
return ARC_CONFIG_NESTED_VALUE;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<valueArgs>")){
|
|
return ARC_CONFIG_VALUE_ARGS;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<array>")){
|
|
return ARC_CONFIG_ARRAY;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<variable>")){
|
|
return ARC_CONFIG_VARIABLE;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<variableName>")){
|
|
return ARC_CONFIG_VARIABLE_NAME;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<variableChar>")){
|
|
return ARC_CONFIG_VARIABLE_CHAR;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<string>")){
|
|
return ARC_CONFIG_STRING;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<stringChars>")){
|
|
return ARC_CONFIG_STRING_CHARS;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<stringChar>")){
|
|
return ARC_CONFIG_STRING_CHAR;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<escapeChar>")){
|
|
return ARC_CONFIG_ESCAPE_CHAR;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<float>")){
|
|
return ARC_CONFIG_FLOAT;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<numberSign>")){
|
|
return ARC_CONFIG_NUMBER_SIGN;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<number>")){
|
|
return ARC_CONFIG_NUMBER_TAG;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<whitespace>")){
|
|
return ARC_CONFIG_WHITESPACE;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<comment>")){
|
|
return ARC_CONFIG_COMMENT;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<lineComment>")){
|
|
return ARC_CONFIG_LINE_COMMENT;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<multiLineComment>")){
|
|
return ARC_CONFIG_MULTI_LINE_COMMENT;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<lineChars>")){
|
|
return ARC_CONFIG_LINE_CHARS;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<multiLineChars>")){
|
|
return ARC_CONFIG_MULTI_LINE_CHARS;
|
|
}
|
|
if(ARC_String_EqualsCStringWithStrlen(string, "<commentChar>")){
|
|
return ARC_CONFIG_COMMENT_CHAR;
|
|
}
|
|
return ~(uint32_t)0;
|
|
}
|
|
|
|
//private function to check hashtable keys used by config
|
|
ARC_Bool ARC_Config_HashtableKeyCompareFn(void *key1, void *key2){
|
|
return (ARC_Bool)strcmp((const char *)key1, (const char *)key2) == 0;
|
|
}
|
|
|
|
//private function to clean up types
|
|
void ARC_Config_TypeHashtableDestroyKeyValueFn(void *key, void *value){
|
|
free((char *)key);
|
|
free((ARC_ConfigType *)value);
|
|
}
|
|
|
|
//private function to clean up groups
|
|
void ARC_Config_GroupHashtableDestroyKeyValueFn(void *key, void *value){
|
|
free((char *)key);
|
|
ARC_Hashtable_Destroy((ARC_Hashtable *)value);
|
|
}
|
|
|
|
//private function to clean up goup data
|
|
void ARC_Config_GroupDataHashtableDestroyKeyValueFn(void *key, void *value){
|
|
free((char *)key);
|
|
|
|
ARC_ConfigTypeData *typeData = (ARC_ConfigTypeData *)value;
|
|
typeData->destroyFn(typeData->config, typeData->data);
|
|
free(typeData);
|
|
}
|
|
|
|
//private empty function to avoid removing references or data freed from an array
|
|
void ARC_ConfigType_EmptyDestroyFn(ARC_Config *config, void *type){
|
|
}
|
|
|
|
//<variableLine> -> <whitespace> <type> <whitespace> <variable> <whitespace> <array> <whitespace> EQUAL <whitespace> <value> <whitespace> SEMICOLON
|
|
void ARC_ConfigData_RunVariableLineTag(ARC_ParserTagToken *tagToken, ARC_Config *config){
|
|
//skip whitespace and check for group name
|
|
ARC_ParserTagToken *childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 1);
|
|
|
|
//get the type
|
|
ARC_String *typeString;
|
|
ARC_String_Create(&typeString, NULL, 0);
|
|
ARC_ParserData_HelperRecurseStringAdd(&typeString, childTagToken);
|
|
|
|
//check if type exists in the types hashtable
|
|
ARC_ConfigType *type = (ARC_ConfigType *)ARC_Hashtable_Get(config->types, typeString->data);
|
|
if(type == NULL){
|
|
//throw an error and return
|
|
arc_errno = ARC_ERRNO_DATA;
|
|
ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_ConfigData_RunVariableLineTag(tagToken, config), type \"%s\" was not registered to config", typeString->data);
|
|
ARC_String_Destroy(typeString);
|
|
return;
|
|
}
|
|
|
|
//cleanup
|
|
ARC_String_Destroy(typeString);
|
|
|
|
//get the variable
|
|
childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 3);
|
|
ARC_String *variableString;
|
|
ARC_String_Create(&variableString, NULL, 0);
|
|
ARC_ParserData_HelperRecurseStringAdd(&variableString, childTagToken);
|
|
|
|
//check if the value is an array
|
|
childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 5);
|
|
ARC_Bool isArray = (ARC_Bool)(ARC_Vector_GetSize(childTagToken->tagTokens) != 0);
|
|
|
|
//check if removing
|
|
if(config->load == ARC_False){
|
|
if(isArray == ARC_True){
|
|
ARC_ConfigTypeData *removingType = ARC_Hashtable_Get(config->currentGroup, (void *)variableString->data);
|
|
ARC_Array *array = (ARC_Array *)removingType->data;
|
|
|
|
for(uint32_t index = 0; index < array->size; index++){
|
|
removingType->destroyFn(config, array->data + index);
|
|
}
|
|
|
|
removingType->destroyFn = ARC_ConfigType_EmptyDestroyFn;
|
|
free(array->data);
|
|
free(array);
|
|
ARC_Hashtable_Remove(config->currentGroup, (void *)variableString->data);
|
|
return;
|
|
}
|
|
|
|
ARC_Hashtable_Remove(config->currentGroup, (void *)variableString->data);
|
|
ARC_String_Destroy(variableString);
|
|
return;
|
|
}
|
|
|
|
//check to see if the current variable is already in the current group hashtable
|
|
ARC_ConfigTypeData *typeData = (ARC_ConfigTypeData *)ARC_Hashtable_Get(config->currentGroup, variableString->data);
|
|
if(typeData != NULL){
|
|
//there is already a value so throw an error and return
|
|
arc_errno = ARC_ERRNO_DATA;
|
|
ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_ConfigData_RunVariableLineTag(tagToken, config), variable \"%s\" already registered to the current group", variableString->data);
|
|
ARC_String_Destroy(variableString);
|
|
return;
|
|
}
|
|
|
|
//copy the string into a cstring that will be stored in the hashtable
|
|
char *nameVariableCStr = malloc(sizeof(char) * (variableString->length + 1));
|
|
strncpy(nameVariableCStr, variableString->data, variableString->length);
|
|
nameVariableCStr[variableString->length] = '\0';
|
|
ARC_String_Destroy(variableString);
|
|
|
|
//get <value>
|
|
childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 9);
|
|
|
|
//check if <value> is a reference
|
|
ARC_String *valueString;
|
|
ARC_String_Create(&valueString, NULL, 0);
|
|
ARC_ParserData_HelperRecurseStringAdd(&valueString, childTagToken);
|
|
void *value = ARC_Hashtable_Get(config->currentGroup, valueString);
|
|
ARC_String_Destroy(valueString);
|
|
|
|
//create where to store either the reference or type data
|
|
typeData = (ARC_ConfigTypeData *)malloc(sizeof(ARC_ConfigTypeData));
|
|
typeData->config = config;
|
|
if(value != NULL){
|
|
//point to the already stored data
|
|
typeData->data = value;
|
|
typeData->destroyFn = ARC_ConfigType_EmptyDestroyFn;
|
|
|
|
//add to the current group hashtable
|
|
ARC_Hashtable_Add(config->currentGroup, (void *)nameVariableCStr, (void *)typeData);
|
|
return;
|
|
}
|
|
|
|
//set the type's destroy function
|
|
typeData->destroyFn = type->destroyFn;
|
|
|
|
//if the value is an array loop through all the nested value's args
|
|
if(isArray == ARC_True){
|
|
ARC_ParserTagToken *nestedValueTagToken = ARC_Vector_Get(childTagToken->tagTokens, 0);
|
|
if(nestedValueTagToken->id != ARC_CONFIG_NESTED_VALUE){
|
|
ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_ConfigData_RunVariableLineTag(tagToken, config), variable \"%s\" was set to be an array but did not pass in a nested value { ... }", nameVariableCStr);
|
|
return;
|
|
}
|
|
|
|
//<nestedValue> -> OPEN_CURLY_BRACE <whitespace> <valueArgs> <whitespace> CLOSE_CURLY_BRACE
|
|
ARC_ParserTagToken *valueArgsTagToken = ARC_Vector_Get(nestedValueTagToken->tagTokens, 2);
|
|
|
|
//create a temporary vector to read in the array
|
|
ARC_VectorInline *typeVector;
|
|
ARC_VectorInline_Create(&typeVector, type->size, NULL, NULL);
|
|
|
|
//<valueArgs> -> <value> <whitespace> COMMA <whitespace> <valueArgs> | <value>
|
|
while(valueArgsTagToken->id == ARC_CONFIG_VALUE_ARGS){
|
|
ARC_ParserTagToken *valueTagToken = ARC_Vector_Get(valueArgsTagToken->tagTokens, 0);
|
|
|
|
//copy the type and store it in the vector
|
|
void *typeData = NULL;
|
|
type->copyFn(&typeData, valueTagToken, config, type->userdata);
|
|
ARC_VectorInline_Add(typeVector, typeData);
|
|
|
|
//if this value args was the last one break
|
|
if(ARC_Vector_GetSize(valueArgsTagToken->tagTokens) == 1){
|
|
break;
|
|
}
|
|
|
|
//get the next valueArgs
|
|
valueArgsTagToken = ARC_Vector_Get(valueArgsTagToken->tagTokens, 4);
|
|
}
|
|
|
|
//copy the data in an ARC_Array
|
|
ARC_Array typeVectorArray = ARC_VectorInline_GetData(typeVector);
|
|
ARC_Array *array = (ARC_Array *)malloc(sizeof(ARC_Array));
|
|
array->size = typeVectorArray.size;
|
|
array->data = NULL;
|
|
|
|
if(typeVectorArray.size != 0){
|
|
//copy the vector into the array's data
|
|
array->data = (void *)malloc(type->size * typeVectorArray.size);
|
|
memcpy(array->data, typeVectorArray.data, type->size * typeVectorArray.size);
|
|
}
|
|
|
|
//set the type data as an array
|
|
typeData->data = array;
|
|
|
|
//add the array to the group hashtable
|
|
ARC_Hashtable_Add(config->currentGroup, (void *)nameVariableCStr, (void *)typeData);
|
|
|
|
//cleanup
|
|
ARC_VectorInline_Destroy(typeVector);
|
|
return;
|
|
}
|
|
|
|
//passed the parsed value into the copy type function and set the destroy function
|
|
type->copyFn(&(typeData->data), childTagToken, config, type->userdata);
|
|
|
|
//add to the current group hashtable
|
|
ARC_Hashtable_Add(config->currentGroup, (void *)nameVariableCStr, (void *)typeData);
|
|
}
|
|
|
|
//<variableLines> -> <variableLine> <whitespace> <variableLines> | <variableLine>
|
|
void ARC_ConfigData_RunVariableLinesTag(ARC_ParserTagToken *tagToken, ARC_Config *config){
|
|
//loop through the tags either going to the next line or the next body
|
|
for(uint32_t index = 0; index < ARC_Vector_GetSize(tagToken->tagTokens); index++){
|
|
ARC_ParserTagToken *childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, index);
|
|
|
|
switch(childTagToken->id){
|
|
//recuse to run the next line
|
|
case ARC_CONFIG_VARIABLE_LINES:
|
|
ARC_ConfigData_RunVariableLinesTag(childTagToken, config);
|
|
if(arc_errno != 0){
|
|
ARC_DEBUG_LOG_ERROR("ARC_ConfigData_RunVariableLinesTag(tagToken, config), config errored when trying to used parsed data for variable lines");
|
|
return;
|
|
}
|
|
continue;
|
|
|
|
//recurse into a variable line tag
|
|
case ARC_CONFIG_VARIABLE_LINE:
|
|
ARC_ConfigData_RunVariableLineTag(childTagToken, config);
|
|
if(arc_errno != 0){
|
|
ARC_DEBUG_LOG_ERROR("ARC_ConfigData_RunVariableLinesTag(tagToken, config), config errored when trying to used parsed data for variable line");
|
|
return;
|
|
}
|
|
continue;
|
|
|
|
//this is for whitespace and any oddities
|
|
default:
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
//<group> -> <whitespace> <groupName> <whitespace> <variable> <whitespace> OPEN_CURLY_BRACE <groupArgs> <whitespace> CLOSE_CURLY_BRACE
|
|
void ARC_ConfigData_RunGroupTag(ARC_ParserTagToken *tagToken, ARC_Config *config){
|
|
//skip whitespace and check for group name
|
|
ARC_ParserTagToken *childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 1);
|
|
|
|
/* ~ <groupName> ~ */
|
|
//get the group name and check if it is named "group"
|
|
//NOTE: this check may be usedful in the future if there is different functionality for group like tag names
|
|
ARC_String *groupName;
|
|
ARC_String_Create(&groupName, NULL, 0);
|
|
ARC_ParserData_HelperRecurseStringAdd(&groupName, childTagToken);
|
|
if(ARC_String_EqualsCStringWithStrlen(groupName, ARC_CONFIG_GROUP_TAG_NAME) == ARC_False){
|
|
//throw an error and return
|
|
arc_errno = ARC_ERRNO_DATA;
|
|
ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_ConfigData_RunGroupTag(tagToken, config), config contained keyword \"%s\" instead of using the correct keyword: \"%s\" ", groupName->data, ARC_CONFIG_GROUP_TAG_NAME);
|
|
ARC_String_Destroy(groupName);
|
|
return;
|
|
}
|
|
|
|
//cleanup
|
|
ARC_String_Destroy(groupName);
|
|
|
|
/* ~ <variable> ~ */
|
|
//get the group's variable name
|
|
childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 3);
|
|
ARC_String *groupVariable;
|
|
ARC_String_Create(&groupVariable, NULL, 0);
|
|
ARC_ParserData_HelperRecurseStringAdd(&groupVariable, childTagToken);
|
|
|
|
//check if removing
|
|
if(config->load == ARC_False){
|
|
/* ~ <groupArgs> ~ */
|
|
childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 6);
|
|
|
|
//<groupArgs> -> <whitespace> <variableLines> | LAMBDA
|
|
if(childTagToken->token == NULL && ARC_Vector_GetSize(childTagToken->tagTokens) == 2){
|
|
ARC_ParserTagToken *variableLines = (ARC_ParserTagToken *)ARC_Vector_Get(childTagToken->tagTokens, 1);
|
|
ARC_ConfigData_RunVariableLinesTag(variableLines, config);
|
|
|
|
//log error if it happens
|
|
if(arc_errno != 0){
|
|
ARC_DEBUG_LOG_ERROR("ARC_ConfigData_RunGroupTag(tagToken, config), config errored when trying to used parsed data for variable lines");
|
|
}
|
|
}
|
|
|
|
//remove an empty hashtable if it is now empty
|
|
if(ARC_Hashtable_GetSize(config->groups)){
|
|
ARC_String_Destroy(groupVariable);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
//get the needed hashtable or create it from the groups hashtable
|
|
ARC_Hashtable *groupHashtable = ARC_Hashtable_Get(config->groups, (void *)groupVariable->data);
|
|
if(groupHashtable == NULL){
|
|
//copy the string into a cstring that will be stored in the hashtable
|
|
char *groupVariableCStr = malloc(sizeof(char) * (groupVariable->length + 1));
|
|
strncpy(groupVariableCStr, groupVariable->data, groupVariable->length);
|
|
groupVariableCStr[groupVariable->length] = '\0';
|
|
|
|
//create the hashtable with the given group name key
|
|
ARC_Hashtable_KeyCompareFn keyCompareFn = ARC_Config_HashtableKeyCompareFn;
|
|
ARC_Hashtable_DestroyKeyValueFn groupDataDestroyKeyValueFn = ARC_Config_GroupDataHashtableDestroyKeyValueFn;
|
|
ARC_Hashtable_Create(&groupHashtable, NULL, &keyCompareFn, &groupDataDestroyKeyValueFn);
|
|
ARC_Hashtable_Add(config->groups, (void *)groupVariableCStr, (void *)groupHashtable);
|
|
}
|
|
|
|
//cleanup
|
|
ARC_String_Destroy(groupVariable);
|
|
|
|
//set the current group to the group just created or found
|
|
config->currentGroup = groupHashtable;
|
|
|
|
/* ~ <groupArgs> ~ */
|
|
childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 6);
|
|
|
|
//<groupArgs> -> <whitespace> <variableLines> | LAMBDA
|
|
if(childTagToken->token == NULL && ARC_Vector_GetSize(childTagToken->tagTokens) == 2){
|
|
ARC_ParserTagToken *variableLines = (ARC_ParserTagToken *)ARC_Vector_Get(childTagToken->tagTokens, 1);
|
|
ARC_ConfigData_RunVariableLinesTag(variableLines, config);
|
|
|
|
//log error if it happens, but as setting the group back is the last thing we shouldn't return
|
|
if(arc_errno != 0){
|
|
ARC_DEBUG_LOG_ERROR("ARC_ConfigData_RunGroupTag(tagToken, config), config errored when trying to used parsed data for variable lines");
|
|
}
|
|
}
|
|
|
|
/* ~ reset current group ~ */
|
|
config->currentGroup = ARC_Hashtable_Get(config->groups, (void *)ARC_CONFIG_DEFAULT_GROUP);
|
|
}
|
|
|
|
//<language> -> <group> <language> | <variableLines> <language> | <whitespace>
|
|
void ARC_ConfigData_RunLanguageTag(ARC_ParserTagToken *tagToken, ARC_Config *config){
|
|
//loop through the tags either going to the next language, group, or variable lines
|
|
for(uint32_t index = 0; index < ARC_Vector_GetSize(tagToken->tagTokens); index++){
|
|
ARC_ParserTagToken *childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, index);
|
|
|
|
switch(childTagToken->id){
|
|
//recuse to run the next line
|
|
case ARC_CONFIG_LANGUAGE:
|
|
ARC_ConfigData_RunLanguageTag(childTagToken, config);
|
|
continue;
|
|
|
|
//recurse into a group tag
|
|
case ARC_CONFIG_GROUP:
|
|
ARC_ConfigData_RunGroupTag(childTagToken, config);
|
|
if(arc_errno != 0){
|
|
ARC_DEBUG_LOG_ERROR("ARC_ConfigData_RunLanguageTag(tagToken, config), config errored when trying to used parsed data for a group");
|
|
return;
|
|
}
|
|
continue;
|
|
|
|
//recurse through variable lines
|
|
case ARC_CONFIG_VARIABLE_LINES:
|
|
ARC_ConfigData_RunVariableLinesTag(childTagToken, config);
|
|
ARC_ConfigData_RunGroupTag(childTagToken, config);
|
|
if(arc_errno != 0){
|
|
ARC_DEBUG_LOG_ERROR("ARC_ConfigData_RunLanguageTag(tagToken, config), config errored when trying to used parsed data for variable lines");
|
|
return;
|
|
}
|
|
continue;
|
|
|
|
//this is for whitespace, comments, and any oddities
|
|
default:
|
|
continue;
|
|
}
|
|
}
|
|
}
|
|
|
|
void ARC_ConfigData_CreateFn(void **data, ARC_ParserTagToken *parsedData, void *userData){
|
|
*data = NULL;
|
|
if(parsedData == NULL || userData == NULL){
|
|
//TODO: error here?
|
|
*data = NULL;
|
|
return;
|
|
}
|
|
|
|
ARC_ConfigData_RunLanguageTag(parsedData, (ARC_Config *)userData);
|
|
}
|
|
|
|
void ARC_ConfigData_DestroyFn(void *data, ARC_Bool clear, void *userData){
|
|
return;
|
|
}
|
|
|
|
void ARC_Config_Create(ARC_Config **config){
|
|
*config = (ARC_Config *)malloc(sizeof(ARC_Config));
|
|
|
|
/* ~ define the language as a string ~ */
|
|
char *languageCString =
|
|
"<language> -> <group> <language> | <variableLines> <language> | <whitespace>\n"
|
|
|
|
"<group> -> <whitespace> <groupName> <whitespace> <variable> <whitespace> OPEN_CURLY_BRACE <groupArgs> <whitespace> CLOSE_CURLY_BRACE\n"
|
|
"<groupName> -> <variable>\n"
|
|
"<groupArgs> -> <whitespace> <variableLines> | LAMBDA\n"
|
|
|
|
"<variableLines> -> <comment> <variableLines> | <variableLine> <whitespace> <variableLines> | <variableLine>\n"
|
|
"<variableLine> -> <whitespace> <type> <whitespace> <variable> <whitespace> <array> <whitespace> EQUAL <whitespace> <value> <whitespace> SEMICOLON\n"
|
|
"<allowSpace> -> SPACE <allowSpace> | TAB <allowSpace> | LAMBDA\n"
|
|
|
|
"<type> -> <variable> | <variable> <whitespace> <array>\n"
|
|
"<value> -> <variable> | <float> | <numberSign> | <string> | <nestedValue>\n"
|
|
"<nestedValue> -> OPEN_CURLY_BRACE <whitespace> <valueArgs> <whitespace> CLOSE_CURLY_BRACE\n"
|
|
"<valueArgs> -> <value> <whitespace> COMMA <whitespace> <valueArgs> | <value>\n"
|
|
|
|
"<array> -> OPEN_BRACKET <whitespace> CLOSE_BRACKET | LAMBDA\n"
|
|
"<variable> -> ALPHA_UPPER_CHAR <variableName> | ALPHA_LOWER_CHAR <variableName> | UNDERSCORE <variableName>\n"
|
|
"<variableName> -> <variableChar> <variableName> | LAMBDA\n"
|
|
"<variableChar> -> ALPHA_UPPER_CHAR | ALPHA_LOWER_CHAR | UNDERSCORE | NUMBER\n"
|
|
|
|
"<string> -> QUOTE <stringChars> QUOTE\n"
|
|
"<stringChars> -> <stringChar> <stringChars> | <escapeChar> <stringChars> | LAMBDA\n"
|
|
"<stringChar> -> TAB | SPACE | BANG | HASH | DOLLAR | PERCENT | AMPERSAND | SINGLE_QUOTE | OPEN_PAREN | CLOSE_PAREN | ASTERISK | PLUS | COMMA | MINUS | PERIOD | SLASH | NUMBER | COLON | SEMICOLON | LESS_THAN | GREATER_THAN | EQUAL | QUESTION_MARK | AT | ALPHA_UPPER_CHAR | OPEN_BRACKET | CLOSE_BRACKET | CARET | UNDERSCORE | GRAVE | ALPHA_LOWER_CHAR | OPEN_CURLY_BRACE | VERTICAL_LINE | CLOSE_CURLY_BRACE | TILDE\n"
|
|
"<escapeChar> -> BACKSLASH BACKSLASH | BACKSLASH QUOTE | BACKSLASH ALPHA_UPPER_CHAR | BACKSLASH ALPHA_LOWER_CHAR\n"
|
|
|
|
"<float> -> <number> PERIOD <number> | <number> PERIOD | PERIOD <number>\n"
|
|
"<numberSign> -> MINUS <number> | <number>\n"
|
|
"<number> -> NUMBER <number> | NUMBER\n"
|
|
|
|
"<whitespace> -> SPACE <whitespace> | TAB <whitespace> | NEWLINE <whitespace> | LAMBDA\n"
|
|
|
|
"<comment> -> <whitespace> <lineComment> | <whitespace> <multiLineComment>\n"
|
|
"<lineComment> -> SLASH SLASH <lineChars> NEWLINE\n"
|
|
"<multiLineComment> -> SLASH ASTERISK <multiLineChars>\n"
|
|
"<lineChars> -> <commentChar> <lineChars> | LAMBDA\n"
|
|
"<multiLineChars> -> ASTERISK SLASH | NEWLINE <multiLineChars> | <commentChar> <multiLineChars>\n"
|
|
"<commentChar> -> TAB | SPACE | BANG | QUOTE | HASH | DOLLAR | PERCENT | AMPERSAND | SINGLE_QUOTE | OPEN_PAREN | CLOSE_PAREN | ASTERISK | PLUS | COMMA | MINUS | PERIOD | SLASH | NUMBER | COLON | SEMICOLON | LESS_THAN | GREATER_THAN | EQUAL | QUESTION_MARK | AT | ALPHA_UPPER_CHAR | OPEN_BRACKET | BACKSLASH | CLOSE_BRACKET | CARET | UNDERSCORE | GRAVE | ALPHA_LOWER_CHAR | OPEN_CURLY_BRACE | VERTICAL_LINE | CLOSE_CURLY_BRACE | TILDE\n";
|
|
|
|
/* ~ define the language as a string ~ */
|
|
ARC_String *languageString;
|
|
ARC_String_CreateWithStrlen(&languageString, languageCString);
|
|
|
|
/* ~ set config as userdata ~ */
|
|
void *userdata = *config;
|
|
|
|
/* ~ create the language ~ */
|
|
ARC_ParserData_CreateFn createCharFn = ARC_ConfigData_CreateFn;
|
|
ARC_ParserData_DestroyFn destroyCharFn = ARC_ConfigData_DestroyFn;
|
|
ARC_Parser_CreateFromString(&((*config)->parser), languageString, ARC_Config_InitLexerRulesFn, ARC_Config_GetStringIdFn, &createCharFn, &destroyCharFn, userdata);
|
|
|
|
/* ~ init types ~ */
|
|
ARC_Hashtable_KeyCompareFn keyCompareFn = ARC_Config_HashtableKeyCompareFn;
|
|
ARC_Hashtable_DestroyKeyValueFn typeDestroyKeyValueFn = ARC_Config_TypeHashtableDestroyKeyValueFn;
|
|
ARC_Hashtable_Create(&((*config)->types), NULL, &keyCompareFn, &typeDestroyKeyValueFn);
|
|
|
|
/* ~ init groups ~ */
|
|
ARC_Hashtable_DestroyKeyValueFn groupDestroyKeyValueFn = ARC_Config_GroupHashtableDestroyKeyValueFn;
|
|
ARC_Hashtable_Create(&((*config)->groups), NULL, &keyCompareFn, &groupDestroyKeyValueFn);
|
|
|
|
//add the default/empty group into the groups
|
|
ARC_Hashtable_DestroyKeyValueFn groupDataDestroyKeyValueFn = ARC_Config_GroupDataHashtableDestroyKeyValueFn;
|
|
|
|
//copy empty group cstring (to be freed by hashtable on cleanup, passing directly would cause a segfault)
|
|
char *emptyCStr = (char *)malloc(sizeof(char) * (strlen(ARC_CONFIG_DEFAULT_GROUP) + 1));
|
|
strcpy(emptyCStr, ARC_CONFIG_DEFAULT_GROUP);
|
|
|
|
//set the current group as empty, then add that into the groups hashtable
|
|
ARC_Hashtable_Create(&((*config)->currentGroup), NULL, &keyCompareFn, &groupDataDestroyKeyValueFn);
|
|
ARC_Hashtable_Add((*config)->groups, (void *)emptyCStr, (*config)->currentGroup);
|
|
|
|
(*config)->load = ARC_True;
|
|
|
|
//cleanup
|
|
ARC_String_Destroy(languageString);
|
|
}
|
|
|
|
void ARC_Config_Destroy(ARC_Config *config){
|
|
ARC_Parser_Destroy(config->parser);
|
|
//NOTE: config->currentGroup does not need to be freed as it is stored in config->groups
|
|
ARC_Hashtable_Destroy(config->groups);
|
|
ARC_Hashtable_Destroy(config->types);
|
|
free(config);
|
|
}
|
|
|
|
void ARC_Config_RegisterType(ARC_Config *config, ARC_String *typeName, ARC_ConfigType type){
|
|
ARC_Config_RegisterTypeWithCStr(config, typeName->data, type);
|
|
}
|
|
|
|
void ARC_Config_RegisterTypeWithCStr(ARC_Config *config, const char *typeNameCStr, ARC_ConfigType type){
|
|
//check if the type key already exists and error if it does
|
|
if(ARC_Hashtable_Get(config->types, (void *)typeNameCStr) != NULL){
|
|
arc_errno = ARC_ERRNO_EXISTS;
|
|
ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_Config_RegisterTypeWithCStr(config, typeName, type), type \"%s\" has already been registered", typeNameCStr);
|
|
return;
|
|
}
|
|
|
|
//copy the string into a cstring for long term storage
|
|
uint64_t typeNameCopyLength = strlen(typeNameCStr) + 1;
|
|
char *typeNameCopy = (char *)malloc(sizeof(char) * typeNameCopyLength);
|
|
strncpy(typeNameCopy, typeNameCStr, typeNameCopyLength);
|
|
typeNameCopy[strlen(typeNameCStr)] = '\0';
|
|
|
|
//copy the type for long term storage
|
|
ARC_ConfigType *typeCopy = (ARC_ConfigType *)malloc(sizeof(ARC_ConfigType));
|
|
*typeCopy = type;
|
|
|
|
//add the type to a hashtable containing all the types
|
|
ARC_Hashtable_Add(config->types, typeNameCopy, typeCopy);
|
|
}
|
|
|
|
void ARC_Config_Add(ARC_Config *config, ARC_String *type, ARC_String *name, void *value){
|
|
//check if type exists in the types hashtable
|
|
ARC_ConfigType *typeValue = (ARC_ConfigType *)ARC_Hashtable_Get(config->types, name->data);
|
|
if(typeValue == NULL){
|
|
//throw an error and return
|
|
arc_errno = ARC_ERRNO_DATA;
|
|
ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_Config_Add(config, type, name, value), type \"%s\" was not registered to config", type->data);
|
|
return;
|
|
}
|
|
|
|
//check if the group separator exists
|
|
uint64_t startSeparatorIndex = ARC_String_FindCStringWithStrlen(name, ARC_CONFIG_GROUP_SEPARATOR);
|
|
if(startSeparatorIndex == ~(uint64_t)0){
|
|
//check to see if the current variable is already in the current group hashtable
|
|
ARC_ConfigTypeData *typeData = (ARC_ConfigTypeData *)ARC_Hashtable_Get(config->currentGroup, name->data);
|
|
if(typeData != NULL){
|
|
//there is already a value so throw an error and return
|
|
arc_errno = ARC_ERRNO_DATA;
|
|
ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_ConfigData_RunVariableLineTag(tagToken, config), variable \"%s\" already registered to the current group", name->data);
|
|
return;
|
|
}
|
|
|
|
//create where to store either the type data
|
|
typeData = (ARC_ConfigTypeData *)malloc(sizeof(ARC_ConfigTypeData));
|
|
typeData->destroyFn = typeValue->destroyFn;
|
|
typeData->data = value;
|
|
|
|
//copy the name into a cstring that will be stored in the hashtable
|
|
char *nameVariableCStr = malloc(sizeof(char) * (name->length + 1));
|
|
strncpy(nameVariableCStr, name->data, name->length);
|
|
nameVariableCStr[name->length] = '\0';
|
|
|
|
//add to the current group hashtable
|
|
ARC_Hashtable_Add(config->currentGroup, (void *)nameVariableCStr, (void *)typeData);
|
|
return;
|
|
}
|
|
|
|
//reset the group the the default group
|
|
config->currentGroup = ARC_Hashtable_Get(config->groups, (void *)ARC_CONFIG_DEFAULT_GROUP);
|
|
|
|
if(startSeparatorIndex != 0){
|
|
//get the group
|
|
startSeparatorIndex--;
|
|
ARC_String *groupString;
|
|
ARC_String_CopySubstring(&groupString, name, 0, startSeparatorIndex);
|
|
|
|
//set the group
|
|
config->currentGroup = ARC_Hashtable_Get(config->groups, (void *)groupString->data);
|
|
|
|
//cleanup
|
|
ARC_String_Destroy(groupString);
|
|
}
|
|
|
|
//get the name
|
|
ARC_String *nameString;
|
|
startSeparatorIndex += strlen(ARC_CONFIG_GROUP_SEPARATOR);
|
|
ARC_String_CopySubstring(&nameString, name, startSeparatorIndex, name->length - startSeparatorIndex);
|
|
|
|
//check to see if the current variable is already in the current group hashtable
|
|
ARC_ConfigTypeData *typeData = (ARC_ConfigTypeData *)ARC_Hashtable_Get(config->currentGroup, nameString->data);
|
|
if(typeData != NULL){
|
|
//there is already a value so throw an error and return
|
|
arc_errno = ARC_ERRNO_DATA;
|
|
ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_ConfigData_RunVariableLineTag(tagToken, config), variable \"%s\" already registered to the current group", name->data);
|
|
return;
|
|
}
|
|
|
|
//create where to store either the type data
|
|
typeData = (ARC_ConfigTypeData *)malloc(sizeof(ARC_ConfigTypeData));
|
|
typeData->destroyFn = typeValue->destroyFn;
|
|
typeData->data = value;
|
|
|
|
//copy the name into a cstring that will be stored in the hashtable
|
|
char *nameVariableCStr = malloc(sizeof(char) * (name->length + 1));
|
|
strncpy(nameVariableCStr, name->data, name->length);
|
|
nameVariableCStr[name->length] = '\0';
|
|
|
|
//add to the current group hashtable
|
|
ARC_Hashtable_Add(config->currentGroup, (void *)nameVariableCStr, (void *)typeData);
|
|
}
|
|
|
|
void ARC_Config_AddWithCStr(ARC_Config *config, const char *type, const char *name, void *value){
|
|
//create and copy strings
|
|
ARC_String *typeString;
|
|
ARC_String *nameString;
|
|
ARC_String_CreateWithStrlen(&typeString, (char *)type);
|
|
ARC_String_CreateWithStrlen(&nameString, (char *)name);
|
|
|
|
//add as an ARC_String
|
|
ARC_Config_Add(config, typeString, nameString, value);
|
|
|
|
//cleanup
|
|
ARC_String_Destroy(nameString);
|
|
ARC_String_Destroy(typeString);
|
|
}
|
|
|
|
void ARC_Config_Remove(ARC_Config *config, ARC_String *name, ARC_Bool isArray){
|
|
//check if the group separator exists
|
|
uint64_t startSeparatorIndex = ARC_String_FindCStringWithStrlen(name, ARC_CONFIG_GROUP_SEPARATOR);
|
|
if(startSeparatorIndex == ~(uint64_t)0){
|
|
//remove the value from the hashtable if it exists
|
|
ARC_ConfigTypeData *typeData = (ARC_ConfigTypeData *)ARC_Hashtable_Get(config->currentGroup, (void *)name->data);
|
|
if(typeData == NULL){
|
|
return;
|
|
}
|
|
|
|
//clean up the values in the array
|
|
if(isArray == ARC_True){
|
|
ARC_Array *array = (ARC_Array *)typeData->data;
|
|
|
|
for(uint32_t index = 0; index < array->size; index++){
|
|
typeData->destroyFn(config, array->data + index);
|
|
}
|
|
|
|
typeData->destroyFn = ARC_ConfigType_EmptyDestroyFn;
|
|
|
|
free(array);
|
|
}
|
|
|
|
//remove the value
|
|
ARC_Hashtable_Remove(config->currentGroup, (void *)name->data);
|
|
return;
|
|
}
|
|
|
|
//reset the group the the default group
|
|
config->currentGroup = ARC_Hashtable_Get(config->groups, (void *)ARC_CONFIG_DEFAULT_GROUP);
|
|
|
|
if(startSeparatorIndex != 0){
|
|
//get the group
|
|
startSeparatorIndex--;
|
|
ARC_String *groupString;
|
|
ARC_String_CopySubstring(&groupString, name, 0, startSeparatorIndex);
|
|
|
|
//set the group
|
|
config->currentGroup = ARC_Hashtable_Get(config->groups, (void *)groupString->data);
|
|
|
|
//cleanup
|
|
ARC_String_Destroy(groupString);
|
|
}
|
|
|
|
//get the name
|
|
ARC_String *nameString;
|
|
startSeparatorIndex += strlen(ARC_CONFIG_GROUP_SEPARATOR);
|
|
ARC_String_CopySubstring(&nameString, name, startSeparatorIndex, name->length - startSeparatorIndex);
|
|
|
|
//remove the value from the hashtable if it exists
|
|
ARC_ConfigTypeData *typeData = (ARC_ConfigTypeData *)ARC_Hashtable_Get(config->currentGroup, (void *)name->data);
|
|
if(typeData != NULL){
|
|
ARC_Hashtable_Remove(config->currentGroup, (void *)name->data);
|
|
}
|
|
ARC_String_Destroy(nameString);
|
|
}
|
|
|
|
void ARC_Config_RemoveWithCStr(ARC_Config *config, const char *name, ARC_Bool isArray){
|
|
//create and copy strings
|
|
ARC_String *nameString;
|
|
ARC_String_CreateWithStrlen(&nameString, (char *)name);
|
|
|
|
//add as an ARC_String
|
|
ARC_Config_Remove(config, nameString, isArray);
|
|
|
|
//cleanup
|
|
ARC_String_Destroy(nameString);
|
|
}
|
|
|
|
void ARC_Config_SetGroup(ARC_Config *config, ARC_String *groupName){
|
|
ARC_Config_SetGroupWithCStr(config, groupName->data);
|
|
}
|
|
|
|
void ARC_Config_SetGroupWithCStr(ARC_Config *config, const char *groupName){
|
|
//try to get the current group
|
|
void *currentGroup = ARC_Hashtable_Get(config->groups, (void *)groupName);
|
|
|
|
//error if the current group does not exist
|
|
if(currentGroup == NULL){
|
|
arc_errno = ARC_ERRNO_NULL;
|
|
ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_Config_SetGroupWithCStr(config, groupName), no group with name \"%s\"", groupName);
|
|
return;
|
|
}
|
|
|
|
//set the current group
|
|
config->currentGroup = currentGroup;
|
|
}
|
|
|
|
void *ARC_Config_Get(ARC_Config *config, ARC_String *name){
|
|
//check if the group separator exists
|
|
uint64_t startSeparatorIndex = ARC_String_FindCStringWithStrlen(name, ARC_CONFIG_GROUP_SEPARATOR);
|
|
if(startSeparatorIndex == ~(uint64_t)0){
|
|
//get the typeData and pass back the data without the cleanup function
|
|
ARC_ConfigTypeData *typeData = (ARC_ConfigTypeData *)ARC_Hashtable_Get(config->currentGroup, (void *)name->data);
|
|
if(typeData == NULL){
|
|
return NULL;
|
|
}
|
|
|
|
return typeData->data;
|
|
}
|
|
|
|
//reset the group the the default group
|
|
config->currentGroup = ARC_Hashtable_Get(config->groups, (void *)ARC_CONFIG_DEFAULT_GROUP);
|
|
|
|
if(startSeparatorIndex != 0){
|
|
//get the group
|
|
startSeparatorIndex--;
|
|
ARC_String *groupString;
|
|
ARC_String_CopySubstring(&groupString, name, 0, startSeparatorIndex);
|
|
|
|
//set the group
|
|
config->currentGroup = ARC_Hashtable_Get(config->groups, (void *)groupString->data);
|
|
|
|
//cleanup
|
|
ARC_String_Destroy(groupString);
|
|
}
|
|
|
|
//get the name
|
|
ARC_String *nameString;
|
|
startSeparatorIndex += strlen(ARC_CONFIG_GROUP_SEPARATOR);
|
|
ARC_String_CopySubstring(&nameString, name, startSeparatorIndex, name->length - startSeparatorIndex);
|
|
|
|
//this will either return the value or NULL
|
|
ARC_ConfigTypeData *typeData = (ARC_ConfigTypeData *)ARC_Hashtable_Get(config->currentGroup, (void *)nameString->data);
|
|
ARC_String_Destroy(nameString);
|
|
if(typeData == NULL){
|
|
return NULL;
|
|
}
|
|
|
|
return typeData->data;
|
|
}
|
|
|
|
void *ARC_Config_GetWithCStr(ARC_Config *config, const char *name){
|
|
//create and copy into ARC_String
|
|
ARC_String *nameString;
|
|
ARC_String_CreateWithStrlen(&nameString, (char *)name);
|
|
|
|
//get the return value
|
|
void *returnValue = ARC_Config_Get(config, nameString);
|
|
|
|
//cleanup
|
|
ARC_String_Destroy(nameString);
|
|
|
|
return returnValue;
|
|
}
|
|
|
|
void ARC_Config_LoadFromString(ARC_Config *config, ARC_String **string){
|
|
config->load = ARC_True;
|
|
ARC_Parser_Parse(config->parser, string);
|
|
}
|
|
|
|
void ARC_Config_LoadFromFile(ARC_Config *config, ARC_String *path){
|
|
config->load = ARC_True;
|
|
ARC_Parser_ParseFile(config->parser, path);
|
|
}
|
|
|
|
void ARC_Config_LoadFromFileWithCStr(ARC_Config *config, const char *path){
|
|
config->load = ARC_True;
|
|
|
|
ARC_String *pathString;
|
|
ARC_String_CreateWithStrlen(&pathString, (char *)path);
|
|
|
|
ARC_Parser_ParseFile(config->parser, pathString);
|
|
|
|
ARC_String_Destroy(pathString);
|
|
}
|
|
|
|
void ARC_Config_UnloadFromString(ARC_Config *config, ARC_String **string){
|
|
config->load = ARC_False;
|
|
ARC_Parser_Parse(config->parser, string);
|
|
}
|
|
|
|
void ARC_Config_UnloadFromFile(ARC_Config *config, ARC_String *path){
|
|
config->load = ARC_False;
|
|
ARC_Parser_ParseFile(config->parser, path);
|
|
}
|
|
|
|
void ARC_Config_InitStd(ARC_Config *config){
|
|
ARC_Config_RegisterTypeWithCStr(config, "bool" , (ARC_ConfigType){ sizeof(ARC_Bool) , ARC_ConfigType_BoolCopyFn , ARC_ConfigType_BoolDestroyFn , NULL });
|
|
ARC_Config_RegisterTypeWithCStr(config, "int8" , (ARC_ConfigType){ sizeof(int8_t) , ARC_ConfigType_Int8CopyFn , ARC_ConfigType_Int8DestroyFn , NULL });
|
|
ARC_Config_RegisterTypeWithCStr(config, "uint8" , (ARC_ConfigType){ sizeof(uint8_t) , ARC_ConfigType_Uint8CopyFn , ARC_ConfigType_Uint8DestroyFn , NULL });
|
|
ARC_Config_RegisterTypeWithCStr(config, "int16" , (ARC_ConfigType){ sizeof(int16_t) , ARC_ConfigType_Int16CopyFn , ARC_ConfigType_Int16DestroyFn , NULL });
|
|
ARC_Config_RegisterTypeWithCStr(config, "uint16" , (ARC_ConfigType){ sizeof(uint16_t) , ARC_ConfigType_Uint16CopyFn, ARC_ConfigType_Uint16DestroyFn, NULL });
|
|
ARC_Config_RegisterTypeWithCStr(config, "int32" , (ARC_ConfigType){ sizeof(int32_t) , ARC_ConfigType_Int32CopyFn , ARC_ConfigType_Int32DestroyFn , NULL });
|
|
ARC_Config_RegisterTypeWithCStr(config, "uint32" , (ARC_ConfigType){ sizeof(uint32_t) , ARC_ConfigType_Uint32CopyFn, ARC_ConfigType_Uint32DestroyFn, NULL });
|
|
ARC_Config_RegisterTypeWithCStr(config, "int64" , (ARC_ConfigType){ sizeof(int64_t) , ARC_ConfigType_Int64CopyFn , ARC_ConfigType_Int64DestroyFn , NULL });
|
|
ARC_Config_RegisterTypeWithCStr(config, "uint64" , (ARC_ConfigType){ sizeof(uint64_t) , ARC_ConfigType_Uint64CopyFn, ARC_ConfigType_Uint64DestroyFn, NULL });
|
|
ARC_Config_RegisterTypeWithCStr(config, "float" , (ARC_ConfigType){ sizeof(float) , ARC_ConfigType_FloatCopyFn , ARC_ConfigType_FloatDestroyFn , NULL });
|
|
ARC_Config_RegisterTypeWithCStr(config, "double" , (ARC_ConfigType){ sizeof(double) , ARC_ConfigType_DoubleCopyFn, ARC_ConfigType_DoubleDestroyFn, NULL });
|
|
ARC_Config_RegisterTypeWithCStr(config, "ARC_String", (ARC_ConfigType){ sizeof(ARC_String), ARC_ConfigType_StringCopyFn, ARC_ConfigType_StringDestroyFn, NULL });
|
|
}
|
|
|
|
void ARC_ConfigType_BoolCopyFn(void **type, ARC_ParserTagToken *parsedData, ARC_Config *config, void *userdata){
|
|
//go into the <variable> tag
|
|
ARC_ParserTagToken *childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(parsedData->tagTokens, 0);
|
|
if(childTagToken->id != ARC_CONFIG_VARIABLE){
|
|
arc_errno = ARC_ERRNO_DATA;
|
|
ARC_DEBUG_LOG_ERROR("ARC_ConfigType_BoolCopyFn(type, parsedData, config, userdata), parsed data was not a <numberSign>");
|
|
*type = NULL;
|
|
return;
|
|
}
|
|
|
|
//get the value as a string
|
|
ARC_String *value;
|
|
ARC_String_Create(&value, NULL, 0);
|
|
ARC_ParserData_HelperRecurseStringAdd(&value, childTagToken);
|
|
|
|
if(ARC_String_EqualsCStringWithStrlen(value, "true") == ARC_True){
|
|
ARC_Bool *boolValue = (ARC_Bool *)malloc(sizeof(ARC_Bool));
|
|
*boolValue = ARC_True;
|
|
ARC_String_Destroy(value);
|
|
|
|
*type = boolValue;
|
|
return;
|
|
}
|
|
|
|
if(ARC_String_EqualsCStringWithStrlen(value, "false") == ARC_True){
|
|
ARC_Bool *boolValue = (ARC_Bool *)malloc(sizeof(ARC_Bool));
|
|
*boolValue = ARC_False;
|
|
ARC_String_Destroy(value);
|
|
|
|
*type = boolValue;
|
|
return;
|
|
}
|
|
|
|
//error if true or false was not passed in
|
|
arc_errno = ARC_ERRNO_DATA;
|
|
ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_ConfigType_BoolCopyFn(type, parsedData, config, userdata), bool can only be \"true\" or \"false\" but was given \"%s\"", value->data);
|
|
ARC_String_Destroy(value);
|
|
*type = NULL;
|
|
}
|
|
|
|
void ARC_ConfigType_BoolDestroyFn(ARC_Config *config, void *type){
|
|
free((ARC_Bool *)type);
|
|
}
|
|
|
|
//private function to make checking ints much easier
|
|
void ARC_ConfigType_IntNumberHelperCopyFn(void **type, ARC_ParserTagToken *parsedData, uint64_t maxSize){
|
|
//go into the <numberSign> tag
|
|
ARC_ParserTagToken *childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(parsedData->tagTokens, 0);
|
|
if(childTagToken->id != ARC_CONFIG_NUMBER_SIGN){
|
|
arc_errno = ARC_ERRNO_DATA;
|
|
ARC_DEBUG_LOG_ERROR("ARC_ConfigType_IntNumberHelperCopyFn(type, parsedData, maxSize), parsed data was not a <numberSign>");
|
|
*type = NULL;
|
|
return;
|
|
}
|
|
|
|
//get the max positive size
|
|
uint64_t maxPositiveSize = maxSize / 2;
|
|
|
|
//set the max size to its max for positive or negative
|
|
int64_t maxSignSize = maxSize / 2;
|
|
if(childTagToken->id != ARC_CONFIG_NUMBER_SIGN){
|
|
maxSize *= 1;
|
|
maxSize--;
|
|
}
|
|
|
|
//check if the first tag is a minus sign and create a string starting with that if it is
|
|
childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(childTagToken->tagTokens, 0);
|
|
ARC_String *intString;
|
|
ARC_String_Create(&intString, NULL, 0);
|
|
|
|
//get the number as a string
|
|
ARC_ParserData_HelperRecurseStringAdd(&intString, parsedData);
|
|
|
|
//TODO: check that this gives the right number
|
|
//get the length of the max size
|
|
uint32_t maxSizeLength = 0;
|
|
for(uint32_t size = maxPositiveSize; 0 < size; size /= 10){
|
|
maxSizeLength++;
|
|
}
|
|
|
|
if(childTagToken->id != ARC_CONFIG_NUMBER_SIGN){
|
|
maxSizeLength++;
|
|
}
|
|
|
|
//if the string is bigger than the possible size return NULL and error
|
|
if(intString->length > maxSizeLength){
|
|
arc_errno = ARC_ERRNO_DATA;
|
|
ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_ConfigType_IntNumberHelperCopyFn(type, parsedData, maxSize), size \"%s\" was bigger or smaller than than the max %lu or min %lu", intString->data, maxPositiveSize, (maxPositiveSize * -1) - 1);
|
|
*type = NULL;
|
|
ARC_String_Destroy(intString);
|
|
return;
|
|
}
|
|
|
|
if(intString->length == maxSize){
|
|
//the max size of a uint64 is -9,223,372,036,854,775,808 so 20 will be big enough for the size
|
|
char maxintCStr[20];
|
|
sprintf(maxintCStr, "%ld", maxSignSize);
|
|
printf("value %s\n", maxintCStr);
|
|
|
|
//check that the number is less than the max
|
|
int8_t stringIndex = maxSize;
|
|
for(int8_t index = maxSize + 1; index >= 0; index--, stringIndex--){
|
|
if(intString->data[stringIndex] > maxintCStr[index]){
|
|
arc_errno = ARC_ERRNO_DATA;
|
|
ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_ConfigType_IntNumberHelperCopyFn(type, parsedData, maxSize), size \"%s\" was bigger than the max of the signed value %lu", intString->data, maxSize);
|
|
*type = NULL;
|
|
ARC_String_Destroy(intString);
|
|
return;
|
|
}
|
|
|
|
//if the number is smaller it is safe to stop checking
|
|
if(intString->data[stringIndex] < maxintCStr[index]){
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//copy the int value
|
|
*type = malloc(maxSizeLength);
|
|
uint64_t valueAsUint64 = ARC_String_ToInt64_t(intString);
|
|
memcpy(*type, &valueAsUint64, maxSizeLength);
|
|
|
|
//cleanup
|
|
ARC_String_Destroy(intString);
|
|
}
|
|
|
|
//private function to make checking uints much easier
|
|
void ARC_ConfigType_UintNumberHelperCopyFn(void **type, ARC_ParserTagToken *parsedData, uint64_t maxSize){
|
|
//go into the <numberSign> tag
|
|
ARC_ParserTagToken *childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(parsedData->tagTokens, 0);
|
|
if(childTagToken->id != ARC_CONFIG_NUMBER_SIGN){
|
|
arc_errno = ARC_ERRNO_DATA;
|
|
ARC_DEBUG_LOG_ERROR("ARC_ConfigType_UintNumberHelperCopyFn(type, parsedData, maxSize), parsed data was not a <numberSign>");
|
|
*type = NULL;
|
|
return;
|
|
}
|
|
|
|
if(childTagToken->id == ARC_CONFIG_MINUS){
|
|
arc_errno = ARC_ERRNO_DATA;
|
|
ARC_DEBUG_LOG_ERROR("ARC_ConfigType_UintNumberHelperCopyFn(type, parsedData, maxSize), parsed data had a minus sign, uint numbers must be positive");
|
|
*type = NULL;
|
|
return;
|
|
}
|
|
|
|
//check if the first tag is a minus sign and create a string starting with that if it is
|
|
childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(childTagToken->tagTokens, 0);
|
|
ARC_String *uintString;
|
|
ARC_String_Create(&uintString, NULL, 0);
|
|
|
|
//get the number as a string
|
|
ARC_ParserData_HelperRecurseStringAdd(&uintString, parsedData);
|
|
|
|
//TODO: check that this gives the right number
|
|
//get the length of the max size
|
|
uint32_t maxSizeLength = 0;
|
|
for(uint32_t size = maxSize; 0 < size; size /= 10){
|
|
maxSizeLength++;
|
|
}
|
|
|
|
//if the string is bigger than the possible size return NULL and error
|
|
if(uintString->length > maxSizeLength){
|
|
arc_errno = ARC_ERRNO_DATA;
|
|
ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_ConfigType_UintNumberHelperCopyFn(type, parsedData, maxSize), size \"%s\" was bigger than the max %lu", uintString->data, maxSize);
|
|
*type = NULL;
|
|
ARC_String_Destroy(uintString);
|
|
return;
|
|
}
|
|
|
|
if(uintString->length == maxSize){
|
|
//the max size of a uint64 is 8,446,744,073,709,551,615 so 20 will be big enough for the size
|
|
char maxuintCStr[20];
|
|
sprintf(maxuintCStr, "%lu", maxSize);
|
|
|
|
//check that the number is less than the max
|
|
int8_t stringIndex = maxSize;
|
|
for(int8_t index = maxSize + 1; index >= 0; index--, stringIndex--){
|
|
if(uintString->data[stringIndex] > maxuintCStr[index]){
|
|
arc_errno = ARC_ERRNO_DATA;
|
|
ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_ConfigType_UintNumberHelperCopyFn(type, parsedData, maxSize), size \"%s\" was bigger than the max %lu", uintString->data, maxSize);
|
|
*type = NULL;
|
|
ARC_String_Destroy(uintString);
|
|
return;
|
|
}
|
|
|
|
//if the number is smaller it is safe to stop checking
|
|
if(uintString->data[stringIndex] < maxuintCStr[index]){
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
//copy the int value
|
|
*type = malloc(maxSizeLength);
|
|
uint64_t valueAsUint64 = ARC_String_ToUint64_t(uintString);
|
|
memcpy(*type, &valueAsUint64, maxSizeLength);
|
|
|
|
//cleanup
|
|
ARC_String_Destroy(uintString);
|
|
}
|
|
|
|
void ARC_ConfigType_Int8CopyFn(void **type, ARC_ParserTagToken *parsedData, ARC_Config *config, void *userdata){
|
|
ARC_ConfigType_IntNumberHelperCopyFn(type, parsedData, ~(uint8_t)0);
|
|
}
|
|
|
|
void ARC_ConfigType_Int8DestroyFn(ARC_Config *config, void *type){
|
|
free((int8_t *)type);
|
|
}
|
|
|
|
void ARC_ConfigType_Uint8CopyFn(void **type, ARC_ParserTagToken *parsedData, ARC_Config *config, void *userdata){
|
|
ARC_ConfigType_UintNumberHelperCopyFn(type, parsedData, ~(uint8_t)0);
|
|
}
|
|
|
|
void ARC_ConfigType_Uint8DestroyFn(ARC_Config *config, void *type){
|
|
free((uint8_t *)type);
|
|
}
|
|
|
|
void ARC_ConfigType_Int16CopyFn(void **type, ARC_ParserTagToken *parsedData, ARC_Config *config, void *userdata){
|
|
ARC_ConfigType_IntNumberHelperCopyFn(type, parsedData, ~(uint16_t)0);
|
|
}
|
|
|
|
void ARC_ConfigType_Int16DestroyFn(ARC_Config *config, void *type){
|
|
free((int16_t *)type);
|
|
}
|
|
|
|
void ARC_ConfigType_Uint16CopyFn(void **type, ARC_ParserTagToken *parsedData, ARC_Config *config, void *userdata){
|
|
ARC_ConfigType_UintNumberHelperCopyFn(type, parsedData, ~(uint16_t)0);
|
|
}
|
|
|
|
void ARC_ConfigType_Uint16DestroyFn(ARC_Config *config, void *type){
|
|
free((uint16_t *)type);
|
|
}
|
|
|
|
void ARC_ConfigType_Int32CopyFn(void **type, ARC_ParserTagToken *parsedData, ARC_Config *config, void *userdata){
|
|
ARC_ConfigType_IntNumberHelperCopyFn(type, parsedData, ~(uint32_t)0);
|
|
}
|
|
|
|
void ARC_ConfigType_Int32DestroyFn(ARC_Config *config, void *type){
|
|
free((int32_t *)type);
|
|
}
|
|
|
|
void ARC_ConfigType_Uint32CopyFn(void **type, ARC_ParserTagToken *parsedData, ARC_Config *config, void *userdata){
|
|
ARC_ConfigType_UintNumberHelperCopyFn(type, parsedData, ~(uint32_t)0);
|
|
}
|
|
|
|
void ARC_ConfigType_Uint32DestroyFn(ARC_Config *config, void *type){
|
|
free((uint32_t *)type);
|
|
}
|
|
|
|
void ARC_ConfigType_Int64CopyFn(void **type, ARC_ParserTagToken *parsedData, ARC_Config *config, void *userdata){
|
|
ARC_ConfigType_IntNumberHelperCopyFn(type, parsedData, ~(uint64_t)0);
|
|
}
|
|
|
|
void ARC_ConfigType_Int64DestroyFn(ARC_Config *config, void *type){
|
|
free((int64_t *)type);
|
|
}
|
|
|
|
void ARC_ConfigType_Uint64CopyFn(void **type, ARC_ParserTagToken *parsedData, ARC_Config *config, void *userdata){
|
|
ARC_ConfigType_UintNumberHelperCopyFn(type, parsedData, ~(uint64_t)0);
|
|
}
|
|
|
|
void ARC_ConfigType_Uint64DestroyFn(ARC_Config *config, void *type){
|
|
free((uint64_t *)type);
|
|
}
|
|
|
|
void ARC_ConfigType_FloatCopyFn(void **type, ARC_ParserTagToken *parsedData, ARC_Config *config, void *userdata){
|
|
//go into the <float> tag
|
|
ARC_ParserTagToken *childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(parsedData->tagTokens, 0);
|
|
if(childTagToken->id != ARC_CONFIG_FLOAT && childTagToken->id != ARC_CONFIG_NUMBER_SIGN){
|
|
arc_errno = ARC_ERRNO_DATA;
|
|
ARC_DEBUG_LOG_ERROR("ARC_ConfigType_FloatCopyFn(type, parsedData, config, userdata), parsed data was not a <float> or <numberSign>");
|
|
*type = NULL;
|
|
return;
|
|
}
|
|
|
|
//get the float as a string
|
|
ARC_String *floatString;
|
|
ARC_String_Create(&floatString, NULL, 0);
|
|
ARC_ParserData_HelperRecurseStringAdd(&floatString, parsedData);
|
|
|
|
//get the value as a float
|
|
char *endptr;
|
|
float value = strtof(floatString->data, &endptr);
|
|
|
|
//error check
|
|
if(floatString->data == endptr){
|
|
arc_errno = ARC_ERRNO_DATA;
|
|
ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_ConfigType_FloatCopyFn(type, parsedData, config, userdata), parsed data \"%s\" was not a <float> or <numberSign>", floatString->data);
|
|
|
|
//cleanup
|
|
ARC_String_Destroy(floatString);
|
|
|
|
//set the type to NULL
|
|
*type = NULL;
|
|
return;
|
|
}
|
|
|
|
//cleanup
|
|
ARC_String_Destroy(floatString);
|
|
|
|
//copy the value into a new double, then pass it out through type
|
|
float *valuePointer = malloc(sizeof(float));
|
|
*valuePointer = value;
|
|
*type = valuePointer;
|
|
}
|
|
|
|
void ARC_ConfigType_FloatDestroyFn(ARC_Config *config, void *type){
|
|
free((float *)type);
|
|
}
|
|
|
|
void ARC_ConfigType_DoubleCopyFn(void **type, ARC_ParserTagToken *parsedData, ARC_Config *config, void *userdata){
|
|
//go into the <float> tag
|
|
//note the float tag means floating point number in this context, and a double does have a flating point
|
|
ARC_ParserTagToken *childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(parsedData->tagTokens, 0);
|
|
if(childTagToken->id != ARC_CONFIG_FLOAT && childTagToken->id != ARC_CONFIG_NUMBER_SIGN){
|
|
arc_errno = ARC_ERRNO_DATA;
|
|
ARC_DEBUG_LOG_ERROR("ARC_ConfigType_FloatCopyFn(type, parsedData, config, userdata), parsed data was not a <float> or <numberSign>");
|
|
*type = NULL;
|
|
return;
|
|
}
|
|
|
|
//get the double as a string
|
|
ARC_String *doubleString;
|
|
ARC_String_Create(&doubleString, NULL, 0);
|
|
ARC_ParserData_HelperRecurseStringAdd(&doubleString, parsedData);
|
|
|
|
//get the value as a double
|
|
char *endptr;
|
|
double value = strtod(doubleString->data, &endptr);
|
|
|
|
//error check
|
|
if(doubleString->data == endptr){
|
|
arc_errno = ARC_ERRNO_DATA;
|
|
ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_ConfigType_FloatCopyFn(type, parsedData, config, userdata), parsed data \"%s\" was not a <float> or <numberSign>", doubleString->data);
|
|
|
|
//cleanup
|
|
ARC_String_Destroy(doubleString);
|
|
|
|
//set the type to NULL
|
|
*type = NULL;
|
|
return;
|
|
}
|
|
|
|
//cleanup
|
|
ARC_String_Destroy(doubleString);
|
|
|
|
//copy the value into a new double, then pass it out through type
|
|
double *valuePointer = malloc(sizeof(double));
|
|
*valuePointer = value;
|
|
*type = valuePointer;
|
|
}
|
|
|
|
void ARC_ConfigType_DoubleDestroyFn(ARC_Config *config, void *type){
|
|
free((double *)type);
|
|
}
|
|
|
|
void ARC_ConfigType_StringCopyFn(void **type, ARC_ParserTagToken *parsedData, ARC_Config *config, void *userdata){
|
|
if(parsedData->id != ARC_CONFIG_STRING){
|
|
arc_errno = ARC_ERRNO_DATA;
|
|
ARC_DEBUG_LOG_ERROR("ARC_ConfigType_StringCopyFn(void **type, ARC_ParserTagToken *parsedData, ARC_Config *config, void *userdata), string was not passed in for ARC_String");
|
|
type = NULL;
|
|
return;
|
|
}
|
|
|
|
//get the string chars between the quotes
|
|
ARC_ParserTagToken *stringCharsTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(parsedData->tagTokens, 1);
|
|
ARC_ParserData_HelperRecurseStringAdd((ARC_String **)type, stringCharsTagToken);
|
|
}
|
|
|
|
void ARC_ConfigType_StringDestroyFn(ARC_Config *config, void *type){
|
|
ARC_String_Destroy(type);
|
|
}
|