#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 #include #include #include struct ARC_Config { ARC_Parser *parser; ARC_Hashtable *types; ARC_Hashtable *groups; ARC_Hashtable *currentGroup; ARC_Bool load; }; typedef struct ARC_ConfigTypeData { 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, "")){ return ARC_CONFIG_LANGUAGE; } if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CONFIG_GROUP; } if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CONFIG_GROUP_NAME; } if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CONFIG_GROUP_ARGS; } if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CONFIG_VARIABLE_LINES; } if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CONFIG_VARIABLE_LINE; } if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CONFIG_ALLOW_SPACE; } if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CONFIG_TYPE; } if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CONFIG_VALUE; } if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CONFIG_NESTED_VALUE; } if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CONFIG_VALUE_ARGS; } if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CONFIG_ARRAY; } if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CONFIG_VARIABLE; } if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CONFIG_VARIABLE_NAME; } if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CONFIG_VARIABLE_CHAR; } if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CONFIG_STRING; } if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CONFIG_STRING_CHARS; } if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CONFIG_STRING_CHAR; } if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CONFIG_ESCAPE_CHAR; } if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CONFIG_NUMBER_SIGN; } if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CONFIG_NUMBER_TAG; } if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CONFIG_WHITESPACE; } if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CONFIG_COMMENT; } if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CONFIG_LINE_COMMENT; } if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CONFIG_MULTI_LINE_COMMENT; } if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CONFIG_LINE_CHARS; } if(ARC_String_EqualsCStringWithStrlen(string, "")){ return ARC_CONFIG_MULTI_LINE_CHARS; } if(ARC_String_EqualsCStringWithStrlen(string, "")){ 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->data); free(typeData); } //private empty function to avoid removing references or data freed from an array void ARC_ConfigType_EmptyDestroyFn(void *type){ } // -> EQUAL 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(array->data + index); } removingType->destroyFn = ARC_ConfigType_EmptyDestroyFn; 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 childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 9); //check if 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)); 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; } // -> OPEN_CURLY_BRACE 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); // -> COMMA | 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); } //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); } // -> | 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; } } } // -> OPEN_CURLY_BRACE 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); /* ~ ~ */ //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); /* ~ ~ */ //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){ /* ~ ~ */ childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 6); // -> | 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; /* ~ ~ */ childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 6); // -> | 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); } // -> | | 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 = " -> | | \n" " -> OPEN_CURLY_BRACE CLOSE_CURLY_BRACE\n" " -> \n" " -> | LAMBDA\n" " -> | | \n" " -> EQUAL SEMICOLON\n" " -> SPACE | TAB | LAMBDA\n" " -> | \n" " -> | | | \n" " -> OPEN_CURLY_BRACE CLOSE_CURLY_BRACE\n" " -> COMMA | \n" " -> OPEN_BRACKET CLOSE_BRACKET | LAMBDA\n" " -> ALPHA_UPPER_CHAR | ALPHA_LOWER_CHAR | UNDERSCORE \n" " -> | LAMBDA\n" " -> ALPHA_UPPER_CHAR | ALPHA_LOWER_CHAR | UNDERSCORE | NUMBER\n" " -> QUOTE QUOTE\n" " -> | | LAMBDA\n" " -> 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" " -> BACKSLASH BACKSLASH | BACKSLASH QUOTE | BACKSLASH ALPHA_UPPER_CHAR | BACKSLASH ALPHA_LOWER_CHAR\n" " -> MINUS | \n" " -> NUMBER | NUMBER\n" " -> SPACE | TAB | NEWLINE | LAMBDA\n" " -> | \n" " -> SLASH SLASH NEWLINE\n" " -> SLASH ASTERISK \n" " -> | LAMBDA\n" " -> ASTERISK SLASH | NEWLINE | \n" " -> 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_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){ //use empty group config->currentGroup = ARC_Hashtable_Get(config->groups, (void *)ARC_CONFIG_DEFAULT_GROUP); //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; } //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){ ARC_ConfigType_BoolCopyFn , ARC_ConfigType_BoolDestroyFn , NULL }); ARC_Config_RegisterTypeWithCStr(config, "int8" , (ARC_ConfigType){ ARC_ConfigType_Int8CopyFn , ARC_ConfigType_Int8DestroyFn , NULL }); ARC_Config_RegisterTypeWithCStr(config, "uint8" , (ARC_ConfigType){ ARC_ConfigType_Uint8CopyFn , ARC_ConfigType_Uint8DestroyFn , NULL }); ARC_Config_RegisterTypeWithCStr(config, "int16" , (ARC_ConfigType){ ARC_ConfigType_Int16CopyFn , ARC_ConfigType_Int16DestroyFn , NULL }); ARC_Config_RegisterTypeWithCStr(config, "uint16" , (ARC_ConfigType){ ARC_ConfigType_Uint16CopyFn, ARC_ConfigType_Uint16DestroyFn, NULL }); ARC_Config_RegisterTypeWithCStr(config, "int32" , (ARC_ConfigType){ ARC_ConfigType_Int32CopyFn , ARC_ConfigType_Int32DestroyFn , NULL }); ARC_Config_RegisterTypeWithCStr(config, "uint32" , (ARC_ConfigType){ ARC_ConfigType_Uint32CopyFn, ARC_ConfigType_Uint32DestroyFn, NULL }); ARC_Config_RegisterTypeWithCStr(config, "int64" , (ARC_ConfigType){ ARC_ConfigType_Int64CopyFn , ARC_ConfigType_Int64DestroyFn , NULL }); ARC_Config_RegisterTypeWithCStr(config, "uint64" , (ARC_ConfigType){ ARC_ConfigType_Uint64CopyFn, ARC_ConfigType_Uint64DestroyFn, NULL }); //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 }); 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){ //go into the 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_BoolNumberHelperCopyFn(type, parsedData, config), parsed data was not a "); *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_BoolNumberHelperCopyFn(type, parsedData, config), bool can only be \"true\" or \"false\" but was given \"%s\"", value->data); ARC_String_Destroy(value); *type = NULL; } void ARC_ConfigType_BoolDestroyFn(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 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, config), parsed data was not a "); *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, config), 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, config), 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 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, config), parsed data was not a "); *type = NULL; return; } if(childTagToken->id == ARC_CONFIG_MINUS){ arc_errno = ARC_ERRNO_DATA; ARC_DEBUG_LOG_ERROR("ARC_ConfigType_UintNumberHelperCopyFn(type, parsedData, config), 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, config), 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, config), 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(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(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(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(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(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(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(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(void *type){ free((uint64_t *)type); } void ARC_ConfigType_FloatCopyFn(void **type, ARC_ParserTagToken *parsedData, ARC_Config *config, void *userdata){ //TODO: write this } void ARC_ConfigType_FloatDestroyFn(void *type){ //TODO: write this } void ARC_ConfigType_DoubleCopyFn(void **type, ARC_ParserTagToken *parsedData, ARC_Config *config, void *userdata){ //TODO: write this } void ARC_ConfigType_DoubleDestroyFn(void *type){ //TODO: write this } 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(void *type){ ARC_String_Destroy(type); }