From 3fbccd97525953f6a91d4614125b9ebe6aa89376 Mon Sep 17 00:00:00 2001 From: herbglitch Date: Sun, 9 Mar 2025 06:03:38 -0600 Subject: [PATCH] basic chemical (config) working, still needs more testing --- include/arc/std/chemical.h | 71 ++++++- src/std/chemical.c | 372 ++++++++++++++++++++++++++++--------- src/std/string.c | 4 - tests/std/chemical.c | 69 ++++++- 4 files changed, 420 insertions(+), 96 deletions(-) diff --git a/include/arc/std/chemical.h b/include/arc/std/chemical.h index 9f70557..7ccab74 100644 --- a/include/arc/std/chemical.h +++ b/include/arc/std/chemical.h @@ -87,7 +87,6 @@ void ARC_Chemical_SetGroupWithCStr(ARC_Chemical *chemical, const char *groupName * @brief get a value from a given keyname * * @note name may be prefaced with :: to specify group - * @note this function uses ARC_Chemical_GetWithCStr so it shares error messages with that function * * @param[in] chemical ARC_Chemical to get value from * @param[in] element name of a variable that has been read in @@ -100,6 +99,7 @@ void *ARC_Chemical_Get(ARC_Chemical *chemical, ARC_String *element); * @brief get a value from a given keyname * * @note name may be prefaced with :: to specify group + * @note this function uses ARC_Chemical_Get so it shares error messages with that function * * @param[in] chemical ARC_Chemical to get value from * @param[in] element name of a variable that has been read in @@ -128,6 +128,75 @@ void ARC_Chemical_UnloadFromString(ARC_Chemical *chemical, ARC_String **string); */ void ARC_Chemical_UnloadFromFile(ARC_Chemical *chemical, ARC_String *data); +#define ARC_CHEMICAL_DEFAULT_GROUP " " +#define ARC_CHEMICAL_GROUP_TAG_NAME "group" +#define ARC_CHEMICAL_GROUP_SEPARATOR "::" + +//the grouping is based on the ascii table, but the ids are sequential to make finding tokens quicker (look at the lexer continious for more explanation) +#define ARC_CHEMICAL_TAB 0x01 +#define ARC_CHEMICAL_NEWLINE 0x02 + +#define ARC_CHEMICAL_SPACE 0x03 +#define ARC_CHEMICAL_BANG 0x04 +#define ARC_CHEMICAL_QUOTE 0x05 +#define ARC_CHEMICAL_HASH 0x06 +#define ARC_CHEMICAL_DOLLAR 0x07 +#define ARC_CHEMICAL_PERCENT 0x08 +#define ARC_CHEMICAL_AMPERSAND 0x09 +#define ARC_CHEMICAL_SINGLE_QUOTE 0x0A +#define ARC_CHEMICAL_OPEN_PAREN 0x0B +#define ARC_CHEMICAL_CLOSE_PAREN 0x0C +#define ARC_CHEMICAL_ASTERISK 0x0D +#define ARC_CHEMICAL_PLUS 0x0E +#define ARC_CHEMICAL_COMMA 0x0F +#define ARC_CHEMICAL_MINUS 0x10 +#define ARC_CHEMICAL_PERIOD 0x11 +#define ARC_CHEMICAL_SLASH 0x12 +#define ARC_CHEMICAL_NUMBER 0x13 + +#define ARC_CHEMICAL_COLON 0x14 +#define ARC_CHEMICAL_SEMICOLON 0x15 +#define ARC_CHEMICAL_LESS_THAN 0x16 +#define ARC_CHEMICAL_GREATER_THAN 0x17 +#define ARC_CHEMICAL_EQUAL 0x18 +#define ARC_CHEMICAL_QUESTION_MARK 0x19 +#define ARC_CHEMICAL_AT 0x1A +#define ARC_CHEMICAL_ALPHA_UPPER_CHAR 0x1B + +#define ARC_CHEMICAL_OPEN_BRACKET 0x1C +#define ARC_CHEMICAL_BACKSLASH 0x1D +#define ARC_CHEMICAL_CLOSE_BRACKET 0x1E +#define ARC_CHEMICAL_CARET 0x1F +#define ARC_CHEMICAL_UNDERSCORE 0x20 +#define ARC_CHEMICAL_GRAVE 0x21 +#define ARC_CHEMICAL_ALPHA_LOWER_CHAR 0x22 + +#define ARC_CHEMICAL_OPEN_CURLY_BRACE 0x23 +#define ARC_CHEMICAL_VERTICAL_LINE 0x24 +#define ARC_CHEMICAL_CLOSE_CURLY_BRACE 0x25 +#define ARC_CHEMICAL_TILDE 0x26 + +#define ARC_CHEMICAL_LANGUAGE 0x27 +#define ARC_CHEMICAL_GROUP 0x28 +#define ARC_CHEMICAL_GROUP_NAME 0x29 +#define ARC_CHEMICAL_GROUP_ARGS 0x2A +#define ARC_CHEMICAL_VARIABLE_LINES 0x2B +#define ARC_CHEMICAL_VARIABLE_LINE 0x2C +#define ARC_CHEMICAL_ALLOW_SPACE 0x2D +#define ARC_CHEMICAL_TYPE 0x2E +#define ARC_CHEMICAL_VALUE 0x2F +#define ARC_CHEMICAL_NESTED_VALUE 0x30 +#define ARC_CHEMICAL_VALUE_ARGS 0x31 +#define ARC_CHEMICAL_VARIABLE 0x32 +#define ARC_CHEMICAL_VARIABLE_NAME 0x33 +#define ARC_CHEMICAL_VARIABLE_CHAR 0x34 +#define ARC_CHEMICAL_STRING 0x35 +#define ARC_CHEMICAL_STRING_CHARS 0x36 +#define ARC_CHEMICAL_STRING_CHAR 0x37 +#define ARC_CHEMICAL_ESCAPE_CHAR 0x38 +#define ARC_CHEMICAL_WHITESPACE 0x39 +#define ARC_CHEMICAL_NUMBER_TAG 0x3A + #ifdef __cplusplus } #endif diff --git a/src/std/chemical.c b/src/std/chemical.c index 141c50e..03a0eef 100644 --- a/src/std/chemical.c +++ b/src/std/chemical.c @@ -23,73 +23,6 @@ typedef struct ARC_ChemicalTypeData { ARC_ChemicalType_DestroyFn destroyFn; } ARC_ChemicalTypeData; -static const char *ARC_CHEMICAL_DEFAULT_GROUP = " "; - -//the grouping is based on the ascii table, but the ids are sequential to make finding tokens quicker (look at the lexer continious for more explanation) -static const uint32_t ARC_CHEMICAL_TAB = 0x01; -static const uint32_t ARC_CHEMICAL_NEWLINE = 0x02; - -static const uint32_t ARC_CHEMICAL_SPACE = 0x03; -static const uint32_t ARC_CHEMICAL_BANG = 0x04; -static const uint32_t ARC_CHEMICAL_QUOTE = 0x05; -static const uint32_t ARC_CHEMICAL_HASH = 0x06; -static const uint32_t ARC_CHEMICAL_DOLLAR = 0x07; -static const uint32_t ARC_CHEMICAL_PERCENT = 0x08; -static const uint32_t ARC_CHEMICAL_AMPERSAND = 0x09; -static const uint32_t ARC_CHEMICAL_SINGLE_QUOTE = 0x0A; -static const uint32_t ARC_CHEMICAL_OPEN_PAREN = 0x0B; -static const uint32_t ARC_CHEMICAL_CLOSE_PAREN = 0x0C; -static const uint32_t ARC_CHEMICAL_ASTERISK = 0x0D; -static const uint32_t ARC_CHEMICAL_PLUS = 0x0E; -static const uint32_t ARC_CHEMICAL_COMMA = 0x0F; -static const uint32_t ARC_CHEMICAL_MINUS = 0x10; -static const uint32_t ARC_CHEMICAL_PERIOD = 0x11; -static const uint32_t ARC_CHEMICAL_SLASH = 0x12; -static const uint32_t ARC_CHEMICAL_NUMBER = 0x13; - -static const uint32_t ARC_CHEMICAL_COLON = 0x14; -static const uint32_t ARC_CHEMICAL_SEMICOLON = 0x15; -static const uint32_t ARC_CHEMICAL_LESS_THAN = 0x16; -static const uint32_t ARC_CHEMICAL_GREATER_THAN = 0x17; -static const uint32_t ARC_CHEMICAL_EQUAL = 0x18; -static const uint32_t ARC_CHEMICAL_QUESTION_MARK = 0x19; -static const uint32_t ARC_CHEMICAL_AT = 0x1A; -static const uint32_t ARC_CHEMICAL_ALPHA_UPPER_CHAR = 0x1B; - -static const uint32_t ARC_CHEMICAL_OPEN_BRACKET = 0x1C; -static const uint32_t ARC_CHEMICAL_BACKSLASH = 0x1D; -static const uint32_t ARC_CHEMICAL_CLOSE_BRACKET = 0x1E; -static const uint32_t ARC_CHEMICAL_CARET = 0x1F; -static const uint32_t ARC_CHEMICAL_UNDERSCORE = 0x20; -static const uint32_t ARC_CHEMICAL_GRAVE = 0x21; -static const uint32_t ARC_CHEMICAL_ALPHA_LOWER_CHAR = 0x22; - -static const uint32_t ARC_CHEMICAL_OPEN_CURLY_BRACE = 0x23; -static const uint32_t ARC_CHEMICAL_VERTICAL_LINE = 0x24; -static const uint32_t ARC_CHEMICAL_CLOSE_CURLY_BRACE = 0x25; -static const uint32_t ARC_CHEMICAL_TILDE = 0x26; - -static const uint32_t ARC_CHEMICAL_LANGUAGE = 0x27; -static const uint32_t ARC_CHEMICAL_GROUP = 0x28; -static const uint32_t ARC_CHEMICAL_GROUP_NAME = 0x29; -static const uint32_t ARC_CHEMICAL_GROUP_ARGS = 0x2A; -static const uint32_t ARC_CHEMICAL_VARIABLE_LINES = 0x2B; -static const uint32_t ARC_CHEMICAL_VARIABLE_LINE = 0x2C; -static const uint32_t ARC_CHEMICAL_ALLOW_SPACE = 0x2D; -static const uint32_t ARC_CHEMICAL_TYPE = 0x2E; -static const uint32_t ARC_CHEMICAL_VALUE = 0x2F; -static const uint32_t ARC_CHEMICAL_NESTED_VALUE = 0x30; -static const uint32_t ARC_CHEMICAL_VALUE_ARGS = 0x31; -static const uint32_t ARC_CHEMICAL_VARIABLE = 0x32; -static const uint32_t ARC_CHEMICAL_VARIABLE_NAME = 0x33; -static const uint32_t ARC_CHEMICAL_VARIABLE_CHAR = 0x34; -static const uint32_t ARC_CHEMICAL_STRING = 0x35; -static const uint32_t ARC_CHEMICAL_STRING_CHARS = 0x36; -static const uint32_t ARC_CHEMICAL_STRING_CHAR = 0x37; -static const uint32_t ARC_CHEMICAL_ESCAPE_CHAR = 0x38; -static const uint32_t ARC_CHEMICAL_WHITESPACE = 0x39; -static const uint32_t ARC_CHEMICAL_NUMBER_TAG = 0x3A; - void ARC_Chemical_InitLexerRulesFn(ARC_Lexer *lexer){ ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_TAB , '\t')); ARC_Lexer_RegisterTokenRule(lexer, ARC_LexerTokenRule_CreateAndReturnMatchCharRule(ARC_CHEMICAL_NEWLINE, '\n')); @@ -325,23 +258,6 @@ uint32_t ARC_Chemical_GetStringIdFn(ARC_String *string){ return ~(uint32_t)0; } -void ARC_ChemicalData_CreateFn(void **data, ARC_ParserTagToken *parsedData, void *userData){ - printf("HERE??\n"); - *data = NULL; - if(parsedData == NULL || userData == NULL){ - printf("Parsed Data was NULL\n"); - //TODO: error here? - *data = NULL; - return; - } - - -} - -void ARC_ChemicalData_DestroyFn(void *data, ARC_Bool clear, void *userData){ - return; -} - //private function to check hashtable keys used by chemical ARC_Bool ARC_Chemical_HashtableKeyCompareFn(void *key1, void *key2){ return (ARC_Bool)strcmp((const char *)key1, (const char *)key2) == 0; @@ -368,6 +284,234 @@ void ARC_Chemical_GroupDataHashtableDestroyKeyValueFn(void *key, void *value){ free(typeData); } +// -> EQUAL SEMICOLON +void ARC_ChemicalData_RunVariableLineTag(ARC_ParserTagToken *tagToken, ARC_Chemical *chemical){ + //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_ChemicalType *type = (ARC_ChemicalType *)ARC_Hashtable_Get(chemical->types, typeString->data); + if(type == NULL){ + //throw an error and return + arc_errno = ARC_ERRNO_DATA; + ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_ChemicalData_RunVariableLineTag(tagToken, chemical), type \"%s\" was not registered to chemical", 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 to see if the current variable is already in the current group hashtable + ARC_ChemicalTypeData *typeData = (ARC_ChemicalTypeData *)ARC_Hashtable_Get(chemical->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_ChemicalData_RunVariableLineTag(tagToken, chemical), 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 *elementVariableCStr = malloc(sizeof(char) * (variableString->length + 1)); + strncpy(elementVariableCStr, variableString->data, variableString->length); + elementVariableCStr[variableString->length] = '\0'; + ARC_String_Destroy(variableString); + + //get + childTagToken = (ARC_ParserTagToken *)ARC_Vector_Get(tagToken->tagTokens, 7); + + //check if is a reference + ARC_String *valueString; + ARC_String_Create(&valueString, NULL, 0); + ARC_ParserData_HelperRecurseStringAdd(&valueString, childTagToken); + void *value = ARC_Hashtable_Get(chemical->currentGroup, valueString); + ARC_String_Destroy(valueString); + + //create where to store either the reference or type data + typeData = (ARC_ChemicalTypeData *)malloc(sizeof(ARC_ChemicalTypeData)); + if(value != NULL){ + //point to the already stored data + typeData->data = value; + typeData->destroyFn = NULL; + + //add to the current group hashtable + ARC_Hashtable_Add(chemical->currentGroup, (void *)elementVariableCStr, (void *)typeData); + return; + } + + //passed the parsed value into the copy type function and set the destroy function + type->copyFn(&(typeData->data), childTagToken, chemical); + typeData->destroyFn = type->destroyFn; + + //add to the current group hashtable + ARC_Hashtable_Add(chemical->currentGroup, (void *)elementVariableCStr, (void *)typeData); +} + +// -> | +void ARC_ChemicalData_RunVariableLinesTag(ARC_ParserTagToken *tagToken, ARC_Chemical *chemical){ +//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_CHEMICAL_VARIABLE_LINES: + ARC_ChemicalData_RunVariableLinesTag(childTagToken, chemical); + if(arc_errno != 0){ + ARC_DEBUG_LOG_ERROR("ARC_ChemicalData_RunVariableLinesTag(tagToken, chemical), chemical errored when trying to used parsed data for variable lines"); + return; + } + continue; + + //recurse into a variable line tag + case ARC_CHEMICAL_VARIABLE_LINE: + ARC_ChemicalData_RunVariableLineTag(childTagToken, chemical); + if(arc_errno != 0){ + ARC_DEBUG_LOG_ERROR("ARC_ChemicalData_RunVariableLinesTag(tagToken, chemical), chemical 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_ChemicalData_RunGroupTag(ARC_ParserTagToken *tagToken, ARC_Chemical *chemical){ + //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_CHEMICAL_GROUP_TAG_NAME) == ARC_False){ + //throw an error and return + arc_errno = ARC_ERRNO_DATA; + ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("ARC_ChemicalData_RunGroupTag(tagToken, chemical), chemical contained keyword \"%s\" instead of using the correct keyword: \"%s\" ", groupName->data, ARC_CHEMICAL_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); + + //get the needed hashtable or create it from the groups hashtable + ARC_Hashtable *groupHashtable = ARC_Hashtable_Get(chemical->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_Chemical_HashtableKeyCompareFn; + ARC_Hashtable_DestroyKeyValueFn groupDataDestroyKeyValueFn = ARC_Chemical_GroupDataHashtableDestroyKeyValueFn; + ARC_Hashtable_Create(&groupHashtable, NULL, &keyCompareFn, &groupDataDestroyKeyValueFn); + ARC_Hashtable_Add(chemical->groups, (void *)groupVariableCStr, (void *)groupHashtable); + } + + //cleanup + ARC_String_Destroy(groupVariable); + + //set the current group to the group just created or found + chemical->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_ChemicalData_RunVariableLinesTag(variableLines, chemical); + + //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_ChemicalData_RunGroupTag(tagToken, chemical), chemical errored when trying to used parsed data for variable lines"); + } + } + + /* ~ reset current group ~ */ + chemical->currentGroup = ARC_Hashtable_Get(chemical->groups, (void *)ARC_CHEMICAL_DEFAULT_GROUP); +} + +// -> | | +void ARC_ChemicalData_RunLanguageTag(ARC_ParserTagToken *tagToken, ARC_Chemical *chemical){ + //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_CHEMICAL_LANGUAGE: + ARC_ChemicalData_RunLanguageTag(childTagToken, chemical); + continue; + + //recurse into a group tag + case ARC_CHEMICAL_GROUP: + ARC_ChemicalData_RunGroupTag(childTagToken, chemical); + if(arc_errno != 0){ + ARC_DEBUG_LOG_ERROR("ARC_ChemicalData_RunLanguageTag(tagToken, chemical), chemical errored when trying to used parsed data for a group"); + return; + } + continue; + + //recurse through variable lines + case ARC_CHEMICAL_VARIABLE_LINES: + ARC_ChemicalData_RunVariableLinesTag(childTagToken, chemical); + ARC_ChemicalData_RunGroupTag(childTagToken, chemical); + if(arc_errno != 0){ + ARC_DEBUG_LOG_ERROR("ARC_ChemicalData_RunLanguageTag(tagToken, chemical), chemical errored when trying to used parsed data for variable lines"); + return; + } + continue; + + //this is for whitespace and any oddities + default: + continue; + } + } +} + +void ARC_ChemicalData_CreateFn(void **data, ARC_ParserTagToken *parsedData, void *userData){ + *data = NULL; + if(parsedData == NULL || userData == NULL){ + //TODO: error here? + *data = NULL; + return; + } + + ARC_ChemicalData_RunLanguageTag(parsedData, (ARC_Chemical *)userData); +} + +void ARC_ChemicalData_DestroyFn(void *data, ARC_Bool clear, void *userData){ + return; +} + void ARC_Chemical_Create(ARC_Chemical **chemical){ *chemical = (ARC_Chemical *)malloc(sizeof(ARC_Chemical)); @@ -438,6 +582,7 @@ void ARC_Chemical_Create(ARC_Chemical **chemical){ } void ARC_Chemical_Destroy(ARC_Chemical *chemical){ + ARC_Parser_Destroy(chemical->parser); //NOTE: chemical->currentGroup does not need to be freed as it is stored in chemical->groups ARC_Hashtable_Destroy(chemical->groups); ARC_Hashtable_Destroy(chemical->types); @@ -457,8 +602,10 @@ void ARC_Chemical_RegisterTypeWithCStr(ARC_Chemical *chemical, const char *typeN } //copy the string into a cstring for long term storage - char *typeNameCopy = malloc(sizeof(char) * strlen(typeNameCStr)); - strcpy(typeNameCopy, typeNameCStr); + 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_ChemicalType *typeCopy = (ARC_ChemicalType *)malloc(sizeof(ARC_ChemicalType)); @@ -488,14 +635,59 @@ void ARC_Chemical_SetGroupWithCStr(ARC_Chemical *chemical, const char *groupName } void *ARC_Chemical_Get(ARC_Chemical *chemical, ARC_String *element){ - return ARC_Chemical_GetWithCStr(chemical, element->data); + //check if the group separator exists + uint64_t startSeparatorIndex = ARC_String_FindCStringWithStrlen(element, ARC_CHEMICAL_GROUP_SEPARATOR); + if(startSeparatorIndex == ~(uint64_t)0){ + //use empty group + chemical->currentGroup = ARC_Hashtable_Get(chemical->groups, (void *)ARC_CHEMICAL_DEFAULT_GROUP); + + //get the typeData and pass back the data without the cleanup function + ARC_ChemicalTypeData *typeData = (ARC_ChemicalTypeData *)ARC_Hashtable_Get(chemical->currentGroup, (void *)element->data); + if(typeData == NULL){ + return NULL; + } + + return typeData->data; + } + + //get the group + startSeparatorIndex--; + ARC_String *groupString; + ARC_String_CopySubstring(&groupString, element, 0, startSeparatorIndex); + + //set the group + chemical->currentGroup = ARC_Hashtable_Get(chemical->groups, (void *)groupString->data); + + //cleanup + ARC_String_Destroy(groupString); + + //get the element + ARC_String *elementString; + startSeparatorIndex += strlen(ARC_CHEMICAL_GROUP_SEPARATOR); + ARC_String_CopySubstring(&elementString, element, startSeparatorIndex, element->length - startSeparatorIndex); + + //this will either return the value or NULL + ARC_ChemicalTypeData *typeData = (ARC_ChemicalTypeData *)ARC_Hashtable_Get(chemical->currentGroup, (void *)elementString->data); + ARC_String_Destroy(elementString); + if(typeData == NULL){ + return NULL; + } + + return typeData->data; } void *ARC_Chemical_GetWithCStr(ARC_Chemical *chemical, const char *element){ - //TODO: set the parent group + //create and copy into ARC_String + ARC_String *elementString; + ARC_String_CreateWithStrlen(&elementString, (char *)element); - //this will either return the value or NULL - return ARC_Hashtable_Get(chemical->currentGroup, (void *)element); + //get the return value + void *returnValue = ARC_Chemical_Get(chemical, elementString); + + //cleanup + ARC_String_Destroy(elementString); + + return returnValue; } void ARC_Chemical_LoadFromString(ARC_Chemical *chemical, ARC_String **string){ diff --git a/src/std/string.c b/src/std/string.c index e5d3e81..aa9cbe1 100644 --- a/src/std/string.c +++ b/src/std/string.c @@ -88,10 +88,6 @@ void ARC_String_CopySubstring(ARC_String **substring, ARC_String *original, uint } char data[length]; - for(uint32_t i = 0; i < length; i++){ - data[i] = 0; - } - strncpy(data, original->data + start, length); ARC_String_Create(substring, data, length); diff --git a/tests/std/chemical.c b/tests/std/chemical.c index 079b43d..319b63e 100644 --- a/tests/std/chemical.c +++ b/tests/std/chemical.c @@ -1,8 +1,65 @@ #include "../test.h" #include "arc/std/errno.h" #include "arc/std/chemical.h" -//#include +#include "arc/std/parser.h" +#include "arc/std/parser/helpers.h" +#include +static const char *testType = "int32"; + +void TEST_ChemicalType_CopyInt32Fn(void **type, ARC_ParserTagToken *parsedData, ARC_Chemical *chemical){ + ARC_String *int32String; + ARC_String_Create(&int32String, NULL, 0); + + ARC_ParserData_HelperRecurseStringAdd(&int32String, parsedData); + + //set the max character size 2,147,483,647 (10 characters) or -2,147,483,648 (11 characters) + uint32_t maxInt32Size = 10; + if(int32String->data[0] == '-'){ + maxInt32Size++; + } + + //if the string is bigger than the possible size return NULL and error + if(int32String->length > maxInt32Size){ + arc_errno = ARC_ERRNO_DATA; + ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("TEST_ChemicalType_CopyInt32Fn(type, parsedData, chemical), size \"%s\" was bigger or smaller than the max 2,147,483,647 or min -2,147,483,648", int32String->data); + *type = NULL; + ARC_String_Destroy(int32String); + return; + } + + if(int32String->length == maxInt32Size){ + char maxint32CStr[10] = "2147483647"; + + //offset starting index and last number if there is a negative + uint8_t stringIndex = 0; + if(int32String->data[0] == '-'){ + stringIndex++; + maxint32CStr[9]++; + } + + for(uint8_t index = 0; index < 10; index++, stringIndex++){ + if(int32String->data[stringIndex] > maxint32CStr[index]){ + arc_errno = ARC_ERRNO_DATA; + ARC_DEBUG_LOG_ERROR_WITH_VARIABLES("TEST_ChemicalType_CopyInt32Fn(type, parsedData, chemical), size \"%s\" was bigger or smaller than the max 2,147,483,647 or min -2,147,483,648", int32String->data); + *type = NULL; + ARC_String_Destroy(int32String); + return; + } + } + } + + //copy the int32_t + *type = malloc(sizeof(int32_t)); + *(int32_t *)(*type) = (int32_t)ARC_String_ToInt64_t(int32String); + + //cleanup + ARC_String_Destroy(int32String); +} + +void TEST_ChemicalType_DestroyInt32Fn(void *type){ + free((int32_t *)type); +} ARC_TEST(Chemical_BasicTest){ ARC_Chemical *chemical; @@ -10,11 +67,21 @@ ARC_TEST(Chemical_BasicTest){ ARC_CHECK(arc_errno == 0); + ARC_ChemicalType int32Type = { + TEST_ChemicalType_CopyInt32Fn, + TEST_ChemicalType_DestroyInt32Fn + }; + ARC_Chemical_RegisterTypeWithCStr(chemical, testType, int32Type); + char *tempCString = "tests/res/std/chemical/first.chemical"; ARC_String *tempString; ARC_String_CreateWithStrlen(&tempString, tempCString); ARC_Chemical_LoadFromFile(chemical, tempString); + int32_t testVal = *(int32_t *)ARC_Chemical_GetWithCStr(chemical, "test::test"); + ARC_CHECK(testVal == 5); + //cleanup + ARC_String_Destroy(tempString); ARC_Chemical_Destroy(chemical); }