2022-10-27 15:16:54 -06:00
# include "arc/std/config.h"
2025-03-24 18:50:15 -06:00
# include "arc/std/array.h"
2025-03-11 00:41:17 -06:00
# include "arc/std/bool.h"
2022-10-27 15:16:54 -06:00
# include "arc/std/errno.h"
2023-01-17 01:59:08 -07:00
# include "arc/std/hashtable.h"
2025-03-11 00:41:17 -06:00
# include "arc/std/parser.h"
2025-03-24 18:50:15 -06:00
# include "arc/std/vector.h"
# include "arc/std/parser/helpers.h"
# include "arc/std/vector/inline.h"
2025-03-11 00:41:17 -06:00
# include <stddef.h>
2023-01-17 01:59:08 -07:00
# include <stdint.h>
2022-10-27 15:16:54 -06:00
# include <stdlib.h>
# include <string.h>
struct ARC_Config {
2025-03-11 00:41:17 -06:00
ARC_Parser * parser ;
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
ARC_Hashtable * types ;
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
ARC_Hashtable * groups ;
ARC_Hashtable * currentGroup ;
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
ARC_Bool load ;
} ;
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
typedef struct ARC_ConfigTypeData {
2025-03-25 04:54:13 -06:00
ARC_Config * config ;
2022-10-27 15:16:54 -06:00
void * data ;
2025-03-11 00:41:17 -06:00
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 , ' ~ ' ) ) ;
}
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
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 ;
}
2023-01-20 22:38:29 -07:00
2025-03-11 00:41:17 -06:00
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 ;
}
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
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 ;
}
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
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 ;
}
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
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 ;
}
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
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 ;
}
2025-03-24 00:32:44 -06:00
if ( ARC_String_EqualsCStringWithStrlen ( string , " <array> " ) ) {
return ARC_CONFIG_ARRAY ;
}
2025-03-11 00:41:17 -06:00
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 ;
}
2025-03-25 03:30:32 -06:00
if ( ARC_String_EqualsCStringWithStrlen ( string , " <float> " ) ) {
return ARC_CONFIG_FLOAT ;
}
2025-03-11 00:41:17 -06:00
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 ;
}
2025-03-24 00:32:44 -06:00
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 ;
}
2025-03-11 00:41:17 -06:00
return ~ ( uint32_t ) 0 ;
2022-10-27 15:16:54 -06:00
}
2025-03-11 00:41:17 -06:00
//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 ;
2022-10-27 15:16:54 -06:00
}
2025-03-11 00:41:17 -06:00
//private function to clean up types
void ARC_Config_TypeHashtableDestroyKeyValueFn ( void * key , void * value ) {
free ( ( char * ) key ) ;
free ( ( ARC_ConfigType * ) value ) ;
}
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
//private function to clean up groups
void ARC_Config_GroupHashtableDestroyKeyValueFn ( void * key , void * value ) {
free ( ( char * ) key ) ;
ARC_Hashtable_Destroy ( ( ARC_Hashtable * ) value ) ;
2023-01-17 01:59:08 -07:00
}
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
//private function to clean up goup data
void ARC_Config_GroupDataHashtableDestroyKeyValueFn ( void * key , void * value ) {
free ( ( char * ) key ) ;
2023-01-20 22:38:29 -07:00
2025-03-11 00:41:17 -06:00
ARC_ConfigTypeData * typeData = ( ARC_ConfigTypeData * ) value ;
2025-03-25 04:54:13 -06:00
typeData - > destroyFn ( typeData - > config , typeData - > data ) ;
2025-03-11 00:41:17 -06:00
free ( typeData ) ;
2022-10-27 15:16:54 -06:00
}
2025-03-24 20:33:43 -06:00
//private empty function to avoid removing references or data freed from an array
2025-03-25 04:54:13 -06:00
void ARC_ConfigType_EmptyDestroyFn ( ARC_Config * config , void * type ) {
2025-03-24 20:33:43 -06:00
}
2025-03-24 00:32:44 -06:00
//<variableLine> -> <whitespace> <type> <whitespace> <variable> <whitespace> <array> <whitespace> EQUAL <whitespace> <value> <whitespace> SEMICOLON
2025-03-11 00:41:17 -06:00
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 ) ;
2023-01-20 22:38:29 -07:00
2025-03-11 00:41:17 -06:00
//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 ) ;
2023-01-17 01:59:08 -07:00
return ;
}
2025-03-11 00:41:17 -06:00
//cleanup
ARC_String_Destroy ( typeString ) ;
2024-08-28 02:57:29 -06:00
2025-03-11 00:41:17 -06:00
//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 ) ;
2022-10-27 15:16:54 -06:00
2025-03-24 20:33:43 -06:00
//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 ) ;
2025-03-11 00:41:17 -06:00
//check if removing
if ( config - > load = = ARC_False ) {
2025-03-24 20:33:43 -06:00
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 + + ) {
2025-03-25 04:54:13 -06:00
removingType - > destroyFn ( config , array - > data + index ) ;
2025-03-24 20:33:43 -06:00
}
removingType - > destroyFn = ARC_ConfigType_EmptyDestroyFn ;
ARC_Hashtable_Remove ( config - > currentGroup , ( void * ) variableString - > data ) ;
return ;
}
2025-03-11 00:41:17 -06:00
ARC_Hashtable_Remove ( config - > currentGroup , ( void * ) variableString - > data ) ;
ARC_String_Destroy ( variableString ) ;
2023-01-17 01:59:08 -07:00
return ;
}
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
//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 ) ;
2023-01-17 01:59:08 -07:00
return ;
}
2025-03-11 00:41:17 -06:00
//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>
2025-03-24 00:32:44 -06:00
childTagToken = ( ARC_ParserTagToken * ) ARC_Vector_Get ( tagToken - > tagTokens , 9 ) ;
2025-03-11 00:41:17 -06:00
//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 ) ) ;
2025-03-25 04:54:13 -06:00
typeData - > config = config ;
2025-03-11 00:41:17 -06:00
if ( value ! = NULL ) {
//point to the already stored data
typeData - > data = value ;
2025-03-24 20:39:34 -06:00
typeData - > destroyFn = ARC_ConfigType_EmptyDestroyFn ;
2025-03-11 00:41:17 -06:00
//add to the current group hashtable
ARC_Hashtable_Add ( config - > currentGroup , ( void * ) nameVariableCStr , ( void * ) typeData ) ;
2023-01-17 01:59:08 -07:00
return ;
}
2025-03-24 18:50:15 -06:00
//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 , sizeof ( void * ) , 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 ( sizeof ( void * ) * typeVectorArray . size ) ;
memcpy ( array - > data , typeVectorArray . data , typeVectorArray . size ) ;
}
2025-03-24 20:33:43 -06:00
//set the type data as an array
typeData - > data = array ;
2025-03-24 18:50:15 -06:00
//add the array to the group hashtable
2025-03-24 20:33:43 -06:00
ARC_Hashtable_Add ( config - > currentGroup , ( void * ) nameVariableCStr , ( void * ) typeData ) ;
2025-03-24 18:50:15 -06:00
//cleanup
ARC_VectorInline_Destroy ( typeVector ) ;
return ;
}
2025-03-11 00:41:17 -06:00
//passed the parsed value into the copy type function and set the destroy function
2025-03-17 18:01:18 -06:00
type - > copyFn ( & ( typeData - > data ) , childTagToken , config , type - > userdata ) ;
2023-01-20 22:38:29 -07:00
2025-03-11 00:41:17 -06:00
//add to the current group hashtable
ARC_Hashtable_Add ( config - > currentGroup , ( void * ) nameVariableCStr , ( void * ) typeData ) ;
}
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
//<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 ;
2023-01-17 01:59:08 -07:00
}
2025-03-11 00:41:17 -06:00
}
}
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
//<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 ;
}
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
//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 " ) ;
}
2023-01-20 22:38:29 -07:00
}
2023-02-23 00:07:18 -07:00
2025-03-11 00:41:17 -06:00
//remove an empty hashtable if it is now empty
if ( ARC_Hashtable_GetSize ( config - > groups ) ) {
ARC_String_Destroy ( groupVariable ) ;
2023-02-23 00:07:18 -07:00
}
2023-01-17 01:59:08 -07:00
return ;
2022-10-27 15:16:54 -06:00
}
2025-03-11 00:41:17 -06:00
//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 ) ;
2023-01-20 22:38:29 -07:00
}
2025-03-11 00:41:17 -06:00
//cleanup
ARC_String_Destroy ( groupVariable ) ;
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
//set the current group to the group just created or found
config - > currentGroup = groupHashtable ;
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
/* ~ <groupArgs> ~ */
childTagToken = ( ARC_ParserTagToken * ) ARC_Vector_Get ( tagToken - > tagTokens , 6 ) ;
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
//<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 ) ;
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
//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 " ) ;
}
2022-10-27 15:16:54 -06:00
}
2025-03-11 00:41:17 -06:00
/* ~ reset current group ~ */
config - > currentGroup = ARC_Hashtable_Get ( config - > groups , ( void * ) ARC_CONFIG_DEFAULT_GROUP ) ;
2023-01-17 01:59:08 -07:00
}
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
//<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 ;
2025-03-24 00:32:44 -06:00
//this is for whitespace, comments, and any oddities
2025-03-11 00:41:17 -06:00
default :
continue ;
}
2023-01-17 01:59:08 -07:00
}
2025-03-11 00:41:17 -06:00
}
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
void ARC_ConfigData_CreateFn ( void * * data , ARC_ParserTagToken * parsedData , void * userData ) {
* data = NULL ;
if ( parsedData = = NULL | | userData = = NULL ) {
//TODO: error here?
* data = NULL ;
2023-01-17 01:59:08 -07:00
return ;
2022-10-27 15:16:54 -06:00
}
2025-03-11 00:41:17 -06:00
ARC_ConfigData_RunLanguageTag ( parsedData , ( ARC_Config * ) userData ) ;
2023-01-17 01:59:08 -07:00
}
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
void ARC_ConfigData_DestroyFn ( void * data , ARC_Bool clear , void * userData ) {
return ;
2022-10-27 15:16:54 -06:00
}
2025-03-11 00:41:17 -06:00
void ARC_Config_Create ( ARC_Config * * config ) {
* config = ( ARC_Config * ) malloc ( sizeof ( ARC_Config ) ) ;
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
/* ~ define the language as a string ~ */
char * languageCString =
2025-03-24 00:32:44 -06:00
" <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 "
2025-03-25 03:30:32 -06:00
" <value> -> <variable> | <float> | <numberSign> | <string> | <nestedValue> \n "
2025-03-24 00:32:44 -06:00
" <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 "
2025-03-25 03:30:32 -06:00
" <float> -> <number> PERIOD <number> | <number> PERIOD | PERIOD <number> \n "
2025-03-24 00:32:44 -06:00
" <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 " ;
2023-01-17 01:59:08 -07:00
2025-03-11 00:41:17 -06:00
/* ~ define the language as a string ~ */
ARC_String * languageString ;
ARC_String_CreateWithStrlen ( & languageString , languageCString ) ;
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
/* ~ set config as userdata ~ */
void * userdata = * config ;
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
/* ~ 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 ) ;
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
/* ~ init types ~ */
ARC_Hashtable_KeyCompareFn keyCompareFn = ARC_Config_HashtableKeyCompareFn ;
ARC_Hashtable_DestroyKeyValueFn typeDestroyKeyValueFn = ARC_Config_TypeHashtableDestroyKeyValueFn ;
ARC_Hashtable_Create ( & ( ( * config ) - > types ) , NULL , & keyCompareFn , & typeDestroyKeyValueFn ) ;
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
/* ~ init groups ~ */
ARC_Hashtable_DestroyKeyValueFn groupDestroyKeyValueFn = ARC_Config_GroupHashtableDestroyKeyValueFn ;
ARC_Hashtable_Create ( & ( ( * config ) - > groups ) , NULL , & keyCompareFn , & groupDestroyKeyValueFn ) ;
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
//add the default/empty group into the groups
ARC_Hashtable_DestroyKeyValueFn groupDataDestroyKeyValueFn = ARC_Config_GroupDataHashtableDestroyKeyValueFn ;
2023-01-17 02:57:57 -07:00
2025-03-11 00:41:17 -06:00
//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 ) ;
2023-01-17 02:57:57 -07:00
2025-03-11 00:41:17 -06:00
//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 ) ;
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
( * config ) - > load = ARC_True ;
2023-01-17 02:57:57 -07:00
2025-03-11 00:41:17 -06:00
//cleanup
ARC_String_Destroy ( languageString ) ;
}
2023-01-17 02:57:57 -07:00
2025-03-11 00:41:17 -06:00
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 ) ;
}
2023-01-17 01:59:08 -07:00
2025-03-11 00:41:17 -06:00
void ARC_Config_RegisterType ( ARC_Config * config , ARC_String * typeName , ARC_ConfigType type ) {
ARC_Config_RegisterTypeWithCStr ( config , typeName - > data , type ) ;
}
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
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 ) ;
2023-01-17 01:59:08 -07:00
return ;
2022-10-27 15:16:54 -06:00
}
2025-03-11 00:41:17 -06:00
//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 ' ;
2023-01-17 01:59:08 -07:00
2025-03-11 00:41:17 -06:00
//copy the type for long term storage
ARC_ConfigType * typeCopy = ( ARC_ConfigType * ) malloc ( sizeof ( ARC_ConfigType ) ) ;
* typeCopy = type ;
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
//add the type to a hashtable containing all the types
ARC_Hashtable_Add ( config - > types , typeNameCopy , typeCopy ) ;
2023-01-17 01:59:08 -07:00
}
2025-03-25 03:30:32 -06:00
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 ) ;
2025-03-25 04:54:13 -06:00
if ( typeValue = = NULL ) {
2025-03-25 03:30:32 -06:00
//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 ) ;
}
2025-03-25 04:54:13 -06:00
void ARC_Config_Remove ( ARC_Config * config , ARC_String * name , ARC_Bool isArray ) {
2025-03-25 03:30:32 -06:00
//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 ) ;
2025-03-25 04:54:13 -06:00
if ( typeData = = NULL ) {
return ;
2025-03-25 03:30:32 -06:00
}
2025-03-25 04:54:13 -06:00
//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 ;
}
//remove the value
ARC_Hashtable_Remove ( config - > currentGroup , ( void * ) name - > data ) ;
2025-03-25 03:30:32 -06:00
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 ) ;
}
2025-03-25 04:54:13 -06:00
void ARC_Config_RemoveWithCStr ( ARC_Config * config , const char * name , ARC_Bool isArray ) {
2025-03-25 03:30:32 -06:00
//create and copy strings
ARC_String * nameString ;
ARC_String_CreateWithStrlen ( & nameString , ( char * ) name ) ;
//add as an ARC_String
2025-03-25 04:54:13 -06:00
ARC_Config_Remove ( config , nameString , isArray ) ;
2025-03-25 03:30:32 -06:00
//cleanup
ARC_String_Destroy ( nameString ) ;
}
2025-03-11 00:41:17 -06:00
void ARC_Config_SetGroup ( ARC_Config * config , ARC_String * groupName ) {
ARC_Config_SetGroupWithCStr ( config , groupName - > data ) ;
}
2023-01-17 01:59:08 -07:00
2025-03-11 00:41:17 -06:00
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 ) ;
2023-01-17 01:59:08 -07:00
2025-03-11 00:41:17 -06:00
//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 ) ;
2023-01-17 01:59:08 -07:00
return ;
}
2022-10-27 15:16:54 -06:00
2025-03-11 00:41:17 -06:00
//set the current group
config - > currentGroup = currentGroup ;
2022-10-27 15:16:54 -06:00
}
2025-03-11 00:41:17 -06:00
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 ;
}
2023-01-17 01:59:08 -07:00
2025-03-11 00:41:17 -06:00
return typeData - > data ;
2023-01-17 01:59:08 -07:00
}
2025-03-25 03:30:32 -06:00
//reset the group the the default group
config - > currentGroup = ARC_Hashtable_Get ( config - > groups , ( void * ) ARC_CONFIG_DEFAULT_GROUP ) ;
2022-10-27 15:16:54 -06:00
2025-03-25 03:30:32 -06:00
if ( startSeparatorIndex ! = 0 ) {
//get the group
startSeparatorIndex - - ;
ARC_String * groupString ;
ARC_String_CopySubstring ( & groupString , name , 0 , startSeparatorIndex ) ;
2022-10-27 15:16:54 -06:00
2025-03-25 03:30:32 -06:00
//set the group
config - > currentGroup = ARC_Hashtable_Get ( config - > groups , ( void * ) groupString - > data ) ;
//cleanup
ARC_String_Destroy ( groupString ) ;
}
2023-01-17 01:59:08 -07:00
2025-03-11 00:41:17 -06:00
//get the name
ARC_String * nameString ;
startSeparatorIndex + = strlen ( ARC_CONFIG_GROUP_SEPARATOR ) ;
ARC_String_CopySubstring ( & nameString , name , startSeparatorIndex , name - > length - startSeparatorIndex ) ;
2023-01-17 01:59:08 -07:00
2025-03-11 00:41:17 -06:00
//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 ;
2023-01-17 01:59:08 -07:00
}
2025-03-11 00:41:17 -06:00
return typeData - > data ;
2023-01-17 01:59:08 -07:00
}
2025-03-11 00:41:17 -06:00
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 ) ;
2023-01-17 02:57:57 -07:00
2025-03-11 00:41:17 -06:00
//get the return value
void * returnValue = ARC_Config_Get ( config , nameString ) ;
2023-01-17 01:59:08 -07:00
2025-03-11 00:41:17 -06:00
//cleanup
ARC_String_Destroy ( nameString ) ;
2023-01-17 02:57:57 -07:00
2025-03-11 00:41:17 -06:00
return returnValue ;
2023-01-17 01:59:08 -07:00
}
2025-03-11 00:41:17 -06:00
void ARC_Config_LoadFromString ( ARC_Config * config , ARC_String * * string ) {
config - > load = ARC_True ;
ARC_Parser_Parse ( config - > parser , string ) ;
2023-01-17 01:59:08 -07:00
}
2025-03-11 00:41:17 -06:00
void ARC_Config_LoadFromFile ( ARC_Config * config , ARC_String * path ) {
config - > load = ARC_True ;
ARC_Parser_ParseFile ( config - > parser , path ) ;
2023-01-17 01:59:08 -07:00
}
2025-03-19 05:13:11 -06:00
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 ) ;
}
2025-03-11 00:41:17 -06:00
void ARC_Config_UnloadFromString ( ARC_Config * config , ARC_String * * string ) {
config - > load = ARC_False ;
ARC_Parser_Parse ( config - > parser , string ) ;
2023-01-17 01:59:08 -07:00
}
2025-03-11 00:41:17 -06:00
void ARC_Config_UnloadFromFile ( ARC_Config * config , ARC_String * path ) {
config - > load = ARC_False ;
ARC_Parser_ParseFile ( config - > parser , path ) ;
2023-01-17 01:59:08 -07:00
}
2025-03-22 03:38:28 -06:00
void ARC_Config_InitStd ( ARC_Config * config ) {
ARC_Config_RegisterTypeWithCStr ( config , " bool " , ( ARC_ConfigType ) { ARC_ConfigType_BoolCopyFn , ARC_ConfigType_BoolDestroyFn , NULL } ) ;
ARC_Config_RegisterTypeWithCStr ( config , " int8 " , ( ARC_ConfigType ) { ARC_ConfigType_Int8CopyFn , ARC_ConfigType_Int8DestroyFn , NULL } ) ;
2025-03-20 05:34:03 -06:00
ARC_Config_RegisterTypeWithCStr ( config , " uint8 " , ( ARC_ConfigType ) { ARC_ConfigType_Uint8CopyFn , ARC_ConfigType_Uint8DestroyFn , NULL } ) ;
2025-03-22 03:38:28 -06:00
ARC_Config_RegisterTypeWithCStr ( config , " int16 " , ( ARC_ConfigType ) { ARC_ConfigType_Int16CopyFn , ARC_ConfigType_Int16DestroyFn , NULL } ) ;
2025-03-20 05:34:03 -06:00
ARC_Config_RegisterTypeWithCStr ( config , " uint16 " , ( ARC_ConfigType ) { ARC_ConfigType_Uint16CopyFn , ARC_ConfigType_Uint16DestroyFn , NULL } ) ;
2025-03-22 03:38:28 -06:00
ARC_Config_RegisterTypeWithCStr ( config , " int32 " , ( ARC_ConfigType ) { ARC_ConfigType_Int32CopyFn , ARC_ConfigType_Int32DestroyFn , NULL } ) ;
2025-03-20 05:34:03 -06:00
ARC_Config_RegisterTypeWithCStr ( config , " uint32 " , ( ARC_ConfigType ) { ARC_ConfigType_Uint32CopyFn , ARC_ConfigType_Uint32DestroyFn , NULL } ) ;
2025-03-22 03:38:28 -06:00
ARC_Config_RegisterTypeWithCStr ( config , " int64 " , ( ARC_ConfigType ) { ARC_ConfigType_Int64CopyFn , ARC_ConfigType_Int64DestroyFn , NULL } ) ;
2025-03-20 05:34:03 -06:00
ARC_Config_RegisterTypeWithCStr ( config , " uint64 " , ( ARC_ConfigType ) { ARC_ConfigType_Uint64CopyFn , ARC_ConfigType_Uint64DestroyFn , NULL } ) ;
2025-03-25 03:30:32 -06:00
ARC_Config_RegisterTypeWithCStr ( config , " float " , ( ARC_ConfigType ) { ARC_ConfigType_FloatCopyFn , ARC_ConfigType_FloatDestroyFn , NULL } ) ;
ARC_Config_RegisterTypeWithCStr ( config , " double " , ( ARC_ConfigType ) { ARC_ConfigType_DoubleCopyFn , ARC_ConfigType_DoubleDestroyFn , NULL } ) ;
2025-03-20 05:34:03 -06:00
ARC_Config_RegisterTypeWithCStr ( config , " ARC_String " , ( ARC_ConfigType ) { ARC_ConfigType_StringCopyFn , ARC_ConfigType_StringDestroyFn , NULL } ) ;
}
void ARC_ConfigType_BoolCopyFn ( void * * type , ARC_ParserTagToken * parsedData , ARC_Config * config , void * userdata ) {
2025-03-22 03:38:28 -06:00
//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 ;
2025-03-25 04:54:13 -06:00
ARC_DEBUG_LOG_ERROR ( " ARC_ConfigType_BoolCopyFn(type, parsedData, config, userdata), parsed data was not a <numberSign> " ) ;
2025-03-22 03:38:28 -06:00
* 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 ;
2025-03-25 04:54:13 -06:00
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 ) ;
2025-03-22 03:38:28 -06:00
ARC_String_Destroy ( value ) ;
* type = NULL ;
2025-03-20 05:34:03 -06:00
}
2025-03-25 04:54:13 -06:00
void ARC_ConfigType_BoolDestroyFn ( ARC_Config * config , void * type ) {
2025-03-22 03:38:28 -06:00
free ( ( ARC_Bool * ) type ) ;
2025-03-20 05:34:03 -06:00
}
//private function to make checking ints much easier
void ARC_ConfigType_IntNumberHelperCopyFn ( void * * type , ARC_ParserTagToken * parsedData , uint64_t maxSize ) {
2025-03-22 03:38:28 -06:00
//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 ;
2025-03-25 03:30:32 -06:00
ARC_DEBUG_LOG_ERROR ( " ARC_ConfigType_IntNumberHelperCopyFn(type, parsedData, maxSize), parsed data was not a <numberSign> " ) ;
2025-03-22 03:38:28 -06:00
* 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 ;
2025-03-25 03:30:32 -06:00
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 ) ;
2025-03-22 03:38:28 -06:00
* 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 ;
2025-03-25 03:30:32 -06:00
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 ) ;
2025-03-22 03:38:28 -06:00
* 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 ) ;
2025-03-20 05:34:03 -06:00
}
//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 ;
2025-03-25 03:30:32 -06:00
ARC_DEBUG_LOG_ERROR ( " ARC_ConfigType_UintNumberHelperCopyFn(type, parsedData, maxSize), parsed data was not a <numberSign> " ) ;
2025-03-20 05:34:03 -06:00
* type = NULL ;
return ;
}
if ( childTagToken - > id = = ARC_CONFIG_MINUS ) {
arc_errno = ARC_ERRNO_DATA ;
2025-03-25 03:30:32 -06:00
ARC_DEBUG_LOG_ERROR ( " ARC_ConfigType_UintNumberHelperCopyFn(type, parsedData, maxSize), parsed data had a minus sign, uint numbers must be positive " ) ;
2025-03-20 05:34:03 -06:00
* 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 ;
2025-03-25 03:30:32 -06:00
ARC_DEBUG_LOG_ERROR_WITH_VARIABLES ( " ARC_ConfigType_UintNumberHelperCopyFn(type, parsedData, maxSize), size \" %s \" was bigger than the max %lu " , uintString - > data , maxSize ) ;
2025-03-20 05:34:03 -06:00
* type = NULL ;
ARC_String_Destroy ( uintString ) ;
return ;
}
if ( uintString - > length = = maxSize ) {
2025-03-22 03:38:28 -06:00
//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 ] ;
2025-03-20 05:34:03 -06:00
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 ;
2025-03-25 03:30:32 -06:00
ARC_DEBUG_LOG_ERROR_WITH_VARIABLES ( " ARC_ConfigType_UintNumberHelperCopyFn(type, parsedData, maxSize), size \" %s \" was bigger than the max %lu " , uintString - > data , maxSize ) ;
2025-03-20 05:34:03 -06:00
* 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 ) ;
}
2025-03-25 04:54:13 -06:00
void ARC_ConfigType_Int8DestroyFn ( ARC_Config * config , void * type ) {
2025-03-20 05:34:03 -06:00
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 ) ;
}
2025-03-25 04:54:13 -06:00
void ARC_ConfigType_Uint8DestroyFn ( ARC_Config * config , void * type ) {
2025-03-20 05:34:03 -06:00
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 ) ;
}
2025-03-25 04:54:13 -06:00
void ARC_ConfigType_Int16DestroyFn ( ARC_Config * config , void * type ) {
2025-03-20 05:34:03 -06:00
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 ) ;
}
2025-03-25 04:54:13 -06:00
void ARC_ConfigType_Uint16DestroyFn ( ARC_Config * config , void * type ) {
2025-03-20 05:34:03 -06:00
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 ) ;
}
2025-03-25 04:54:13 -06:00
void ARC_ConfigType_Int32DestroyFn ( ARC_Config * config , void * type ) {
2025-03-20 05:34:03 -06:00
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 ) ;
}
2025-03-25 04:54:13 -06:00
void ARC_ConfigType_Uint32DestroyFn ( ARC_Config * config , void * type ) {
2025-03-20 05:34:03 -06:00
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 ) ;
}
2025-03-25 04:54:13 -06:00
void ARC_ConfigType_Int64DestroyFn ( ARC_Config * config , void * type ) {
2025-03-20 05:34:03 -06:00
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 ) ;
}
2025-03-25 04:54:13 -06:00
void ARC_ConfigType_Uint64DestroyFn ( ARC_Config * config , void * type ) {
2025-03-20 05:34:03 -06:00
free ( ( uint64_t * ) type ) ;
}
void ARC_ConfigType_FloatCopyFn ( void * * type , ARC_ParserTagToken * parsedData , ARC_Config * config , void * userdata ) {
2025-03-25 03:30:32 -06:00
//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 ;
2025-03-20 05:34:03 -06:00
}
2025-03-25 04:54:13 -06:00
void ARC_ConfigType_FloatDestroyFn ( ARC_Config * config , void * type ) {
2025-03-25 03:30:32 -06:00
free ( ( float * ) type ) ;
2025-03-20 05:34:03 -06:00
}
void ARC_ConfigType_DoubleCopyFn ( void * * type , ARC_ParserTagToken * parsedData , ARC_Config * config , void * userdata ) {
2025-03-25 03:30:32 -06:00
//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 ;
2025-03-20 05:34:03 -06:00
}
2025-03-25 04:54:13 -06:00
void ARC_ConfigType_DoubleDestroyFn ( ARC_Config * config , void * type ) {
2025-03-25 03:30:32 -06:00
free ( ( double * ) type ) ;
2025-03-20 05:34:03 -06:00
}
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 ) ;
}
2025-03-25 04:54:13 -06:00
void ARC_ConfigType_StringDestroyFn ( ARC_Config * config , void * type ) {
2025-03-20 05:34:03 -06:00
ARC_String_Destroy ( type ) ;
}