config and string reworked, hashtable updated to use arc_errno

This commit is contained in:
herbglitch 2023-01-17 01:59:08 -07:00
parent 0bbce28469
commit f8d987da8e
12 changed files with 1121 additions and 657 deletions

View file

@ -1,8 +1,11 @@
#include "arc/std/config.h"
#include "arc/std/errno.h"
#include "arc/std/hashtable.h"
#include "arc/std/io.h"
#include "arc/std/string.h"
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
@ -20,72 +23,48 @@ typedef struct ARC_ConfigKey {
} ARC_ConfigKey;
typedef struct ARC_ConfigTypeTemplate {
ARC_ConfigKey *key;
ARC_ConfigKeyDelete Delete;
void *data;
} ARC_ConfigTypeTemplate;
typedef struct ARC_DeleteUserData {
ARC_Config *config;
int8_t ARC_Config_KeyComp(void *key1, size_t *key1size, void *key2, size_t *key2size);
const char* data;
ARC_StringSubstr *subdata;
} ARC_DeleteUserData;
void ARC_Config_CreateGroup(ARC_Config *config, ARC_String *name);
void ARC_Config_DestroyGroup(ARC_HashtableNode *group, void *userdata);
int32_t ARC_Config_KeyComp(void *key1, size_t *key1size, void *key2, size_t *key2size){
if(*key1size - *key2size){ return -1; }
return strncmp((const char *)key1, (const char *)key2, *key1size);
void ARC_Config_DestroyGroupNode(ARC_HashtableNode *node , void *userdata);
void ARC_Config_RemoveKey(ARC_HashtableNode *node, void *userdata);
void ARC_Config_AddKey(ARC_Config *config, ARC_String *type, ARC_ConfigKeyRead keyRead, ARC_ConfigKeyDelete keyDelete){
ARC_ConfigKey *newKey = (ARC_ConfigKey *)malloc(sizeof(ARC_ConfigKey));
newKey->Read = keyRead;
newKey->Delete = keyDelete;
char *typeval = (char *)malloc(sizeof(char) * type->length);
strncpy(typeval, type->data, type->length);
ARC_Hashtable_Add(config->keys, (void *)typeval, type->length, newKey);
}
int32_t ARC_ConfigKey_Add(ARC_Config *config, char *type, ARC_ConfigKeyRead keyRead, ARC_ConfigKeyDelete keyDelete){
ARC_ConfigKey *temp = (ARC_ConfigKey *)malloc(sizeof(ARC_ConfigKey));
temp->Read = keyRead;
temp->Delete = keyDelete;
return ARC_Hashtable_Add(config->keys, (void *)type, strlen(type), (void *)temp);
void ARC_Config_AddKeyCString(ARC_Config *config, const char *type, uint64_t length, ARC_ConfigKeyRead keyRead, ARC_ConfigKeyDelete keyDelete){
ARC_ConfigKey *newKey = (ARC_ConfigKey *)malloc(sizeof(ARC_ConfigKey));
newKey->Read = keyRead;
newKey->Delete = keyDelete;
char *typeval = (char *)malloc(sizeof(char) * length);
strncpy(typeval, type, length);
ARC_Hashtable_Add(config->keys, (void *)typeval, length, newKey);
}
int32_t ARC_ConfigKey_Destroy(ARC_HashtableNode *node, void *userdata){
if(!node->data){ return ARC_ERRNO_NULL; }
free((ARC_ConfigKey *)node->data);
return 0;
}
int32_t ARC_ConfigGroup_Create(ARC_Config *config, const char *name){
ARC_Hashtable *data;
ARC_Hashtable_Create(&data, ARC_GROUP_DATA_BUCKET_SIZE, NULL, ARC_Config_KeyComp);
char *group = (char *) malloc(sizeof(char) * strlen(name));
strncpy(group, name, strlen(name));
return ARC_Hashtable_Add(config->groups, (void *)group, strlen(name), (void *)data);
}
int32_t ARC_ConfigGroupNode_Destroy(ARC_HashtableNode *node, void *userdata){
free((char *)node->key);
ARC_ConfigTypeTemplate *temp = (ARC_ConfigTypeTemplate *)node->data;
if(temp->key){
ARC_DeleteUserData *deldata = (ARC_DeleteUserData *)userdata;
temp->key->Delete(deldata->config, deldata->data, deldata->subdata, temp->data);
}
free(temp);
return 0;
}
int32_t ARC_ConfigGroup_Destroy(ARC_HashtableNode *group, void *userdata){
free((char *)group->key);
return ARC_Hashtable_Destroy((ARC_Hashtable *)group->data, ARC_ConfigGroupNode_Destroy, userdata);
}
int32_t ARC_Config_Create(ARC_Config **config, ARC_ConfigKey_AddFunc keysAdd){
*config = (ARC_Config *) malloc(sizeof(ARC_Config));
void ARC_Config_Create(ARC_Config **config){
*config = (ARC_Config *)malloc(sizeof(ARC_Config));
(*config)->currgroup = NULL;
ARC_Hashtable *groups;
ARC_Hashtable_Create(&groups, ARC_GROUP_BUCKET_SIZE, NULL, ARC_Config_KeyComp);
(*config)->groups = groups;
ARC_ConfigGroup_Create(*config, "");
ARC_Config_CreateGroup(*config, NULL);
ARC_Hashtable *keys;
ARC_Hashtable_Create(&keys, ARC_KEY_BUCKET_SIZE, NULL, ARC_Config_KeyComp);
@ -94,323 +73,474 @@ int32_t ARC_Config_Create(ARC_Config **config, ARC_ConfigKey_AddFunc keysAdd){
#ifdef ARC_DEFAULT_CONFIG
ARC_Defaults_ConfigKey_Create(*config);
#endif
if(keysAdd){ keysAdd(*config); }
return 0;
}
int32_t ARC_Config_Destroy(ARC_Config *config){
ARC_DeleteUserData deldata = { .config = config, .data = NULL, .subdata = NULL };
int32_t err = ARC_Hashtable_Destroy(config->groups, ARC_ConfigGroup_Destroy, (void *)&deldata);
if(err){ return err; }
err = ARC_Hashtable_Destroy(config->keys, ARC_ConfigKey_Destroy, NULL);
if(err){ return err; }
void ARC_Config_Destroy(ARC_Config *config){
ARC_Hashtable_Destroy(config->groups, ARC_Config_DestroyGroup, (void *)&config);
ARC_Hashtable_Destroy(config->keys , ARC_Config_RemoveKey , NULL );
free(config);
return 0;
}
int32_t ARC_Config_Get(ARC_Config *config, char *keyname, void **value){
uint64_t len = 0;
ARC_ConfigTypeTemplate *temp;
int32_t err = ARC_String_Find(keyname, (char *)"::", &len);
if(err){ return err; }
if(len != ~((uint64_t)0)){
char group[len + 1];
strncpy(group, keyname, len);
group[len] = '\0';
ARC_Hashtable *currgroup = config->currgroup;
err = ARC_Config_SetGroup(config, group);
if(err){ return err; }
char *namestr = (len + 2) + keyname;
char name[strlen(namestr)];
strcpy(name, namestr);
err = ARC_Hashtable_Get(config->currgroup, (void *)name, strlen(name), (void **)&temp);
if(err){ return err; }
config->currgroup = currgroup;
*value = temp->data;
return 0;
}
err = ARC_Hashtable_Get(config->currgroup, (void *)keyname, strlen(keyname), (void **)&temp);
if(err){ return err; }
*value = temp->data;
return 0;
}
int32_t ARC_Config_Remove(ARC_Config *config, const char *keyname, const char* data, ARC_StringSubstr *subdata){
ARC_DeleteUserData deldata = { .config = config, .data = data, .subdata = subdata };
return ARC_Hashtable_Remove(config->currgroup, (void *)keyname, strlen(keyname), ARC_ConfigGroupNode_Destroy, (void *)&deldata);
}
int32_t ARC_Config_SetGroup(ARC_Config *config, char *groupstr){
int err = ARC_Hashtable_Get(config->groups, groupstr, strlen(groupstr), (void **)&(config->currgroup));
if(err && err != ARC_ERRNO_NULL){ return err; }
if(!(config->currgroup)){
err = ARC_ConfigGroup_Create(config, groupstr);
if(err){ return err; }
err = ARC_Hashtable_Get(config->groups, groupstr, strlen(groupstr), (void **)&(config->currgroup));
if(err){ return err; }
}
return 0;
}
void ARC_ConfigPath_Create(char *data, ARC_StringSubstr *subpath, char **path){
if(*(data + subpath->index) == '~'){
*path = (char *) malloc(sizeof(char) * (subpath->length + strlen(ARC_HOME_PATH) + 1));
strcpy(*path, ARC_HOME_PATH);
strncpy((*path) + strlen(ARC_HOME_PATH) - 1, data + subpath->index, subpath->length);
(*path)[subpath->length + strlen(ARC_HOME_PATH)] = '\0';
void ARC_Config_SetGroup(ARC_Config *config, ARC_String *groupname){
if(groupname == NULL){
ARC_Hashtable_Get(config->groups, (void *)" ", 1, (void **)&(config->currgroup));
return;
}
*path = (char *) malloc(sizeof(char) * (subpath->length + 1));
strncpy(*path, data + subpath->index, subpath->length);
(*path)[subpath->length] = '\0';
}
void ARC_ConfigPath_Destroy(char *url){
free(url);
}
int32_t ARC_Config_Recurse(ARC_Config *config, char *data, uint64_t *size, char *groupstr, ARC_StringSubstr *subkey, uint8_t *command);
int32_t ARC_ConfigKey_Command(ARC_Config *config, char *data, uint64_t *size, ARC_StringSubstr *subkey){
ARC_StringSubstr subcommand = { subkey->index + 1, 0 };
int32_t err = ARC_String_Find(data + subcommand.index, " ", &(subcommand.length));
if(err){ return err; }
if(subcommand.length == ~((uint64_t)0)){ return ARC_ERRNO_DATA; }
subkey->index += subcommand.length + 1;
ARC_StringSubstr_StripEnds(data, NULL, &subcommand);
if(strncmp("load", data + subcommand.index, strlen("load")) && strncmp("unload", data + subcommand.index, strlen("unload"))){ return ARC_ERRNO_DATA; }
ARC_StringSubstr subpath = { subkey->index, 0 };
err = ARC_String_Find(data + subpath.index, (char *)"\"", &(subpath.index));
if(err){ return err; }
if(subpath.length == ~((uint64_t)0)){ return ARC_ERRNO_DATA; }
subkey->index += subpath.length + 2; //we want to skip over the first \" that is why it is 2 not 1
subpath = (ARC_StringSubstr) { subkey->index, 0 };
err = ARC_String_Find(data + subpath.index, (char *)"\"", &(subpath.length));
if(err){ return err; }
if(subpath.length == ~((uint64_t)0)){ return ARC_ERRNO_DATA; }
subkey->index += subpath.length + 1;
char *path;
ARC_ConfigPath_Create(data, &subpath, &path);
if (!strncmp( "load", data + subcommand.index, strlen( "load"))){ err = ARC_Config_FileIO(config, path, ARC_CONFIG_FILE_IO_LOAD ); }
else if(!strncmp("unload", data + subcommand.index, strlen("unload"))){ err = ARC_Config_FileIO(config, path, ARC_CONFIG_FILE_IO_UNLOAD); }
else { return ARC_ERRNO_DATA; }
ARC_ConfigPath_Destroy(path);
return err;
}
int32_t ARC_ConfigKey_Comment(ARC_Config *config, char *data, uint64_t *size, ARC_StringSubstr *subkey){
uint64_t commentlen = 0;
if(data[subkey->index + 1] == '*'){
int32_t err = ARC_String_Find(data + subkey->index, (char *)"*/", &commentlen);
if(err){ return err; }
subkey->index += commentlen + 1;
return 0;
ARC_Hashtable_Get(config->groups, (void *)groupname->data, groupname->length, (void **)&(config->currgroup));
if(arc_errno && arc_errno != ARC_ERRNO_NULL){
return;
}
int32_t err = ARC_String_Find(data + subkey->index, (char *)"\n", &commentlen);
if(err){ return err; }
if(config->currgroup){
return;
}
subkey->index += commentlen + 1;
return 0;
ARC_Config_CreateGroup(config, groupname);
if(arc_errno){
return;
}
ARC_Hashtable_Get(config->groups, (void *)groupname->data, groupname->length, (void **)&(config->currgroup));
}
int32_t ARC_ConfigKey_Group(ARC_Config *config, char *data, uint64_t *size, ARC_StringSubstr *subkey, uint8_t *command){
ARC_StringSubstr subgroup = { subkey->index, 0 };
int32_t err = ARC_String_Find(data + subgroup.index, "{", &(subgroup.length));
if(err){ return err; }
if(subgroup.length == ~((uint64_t)0)){ return ARC_ERRNO_DATA; }
subkey->index += subgroup.length + 1;
void ARC_Config_Get(ARC_Config *config, ARC_String *keyname, void **value){
ARC_ConfigTypeTemplate *temp;
ARC_StringSubstr_StripEnds(data, NULL, &subgroup);
ARC_String *separator;
ARC_String_Create(&separator, "::", 2);
uint64_t length = ARC_String_Find(keyname, separator);
char groupstr[subgroup.length + 1];
strncpy(groupstr, data + subgroup.index, subgroup.length);
groupstr[subgroup.length] = '\0';
if(arc_errno){
//TODO: Debug info here
*value = NULL;
return;
}
return ARC_Config_Recurse(config, data, size, groupstr, subkey, command);
if(length != ~((uint64_t)0)){
ARC_String *group;
ARC_String_CopySubstring(&group, keyname, 0, length);
ARC_Hashtable *currgroup = config->currgroup;
ARC_Config_SetGroup(config, group);
if(arc_errno){
ARC_String_Destroy(group);
*value = NULL;
return;
}
ARC_String *name;
ARC_String_CopySubstring(&name, keyname, length + 2, keyname->length - (length + 2));
ARC_Hashtable_Get(config->currgroup, (void *)name->data, name->length, (void **)&temp);
config->currgroup = currgroup;
*value = temp->data;
return;
}
ARC_Hashtable_Get(config->currgroup, (void *)keyname->data, keyname->length, (void **)&temp);
if(arc_errno || temp == NULL){
*value = NULL;
return;
}
*value = temp->data;
}
int32_t ARC_ConfigKey_Load(ARC_Config *config, char *data, uint64_t *size, char *keyname, ARC_StringSubstr *subkey){
void ARC_Config_Recurse(ARC_Config *config, ARC_String **data, ARC_String *groupstr, uint8_t *command);
void ARC_Config_SetKeyGroup(ARC_Config *config, ARC_String **data, uint8_t *command){
uint64_t index = ARC_String_FindCString(*data, " ", 1);
uint64_t nextIndex = ARC_String_FindCString(*data, "{", 1);
if(index == ~(uint64_t)0 || nextIndex == ~(uint64_t)0){
arc_errno = ARC_ERRNO_DATA;
}
if(arc_errno){
return;
}
ARC_String *name, *temp;
ARC_String_CopySubstring(&temp, *data, index, nextIndex);
ARC_String_StripEndsWhitespace(temp, &name);
ARC_String_Destroy(temp);
temp = *data;
ARC_String_RemoveSection(data, temp, nextIndex + 1, (*data)->length - (nextIndex + 1));
ARC_String_Destroy(temp);
ARC_Config_Recurse(config, data, name, command);
ARC_String_Destroy(name);
}
void ARC_Config_LoadFromKey(ARC_Config *config, ARC_String *keyType, ARC_String *name, ARC_String *value){
ARC_ConfigKey *key;
int32_t err = ARC_Hashtable_Get(config->keys, (void *)keyname, strlen(keyname), (void **)&key);
if(err){ return err; }
ARC_StringSubstr subname = { subkey->index, 0 };
err = ARC_String_Find(data + subname.index, (char *)"=", &(subname.length));
if(err){ return err; }
if(subname.length == ~((uint64_t)0)){ return ARC_ERRNO_DATA; }
subkey->index += subname.length + 1;
ARC_StringSubstr_StripEnds(data, NULL, &subname);
ARC_StringSubstr subvalue = { subkey->index, 0 };
err = ARC_String_Find(data + subvalue.index, (char *)";", &(subvalue.length));
if(err){ return err; }
if(subvalue.length == ~((uint64_t)0)){ return ARC_ERRNO_DATA; }
subkey->index += subvalue.length + 1;
ARC_StringSubstr_StripEnds(data, NULL, &subvalue);
ARC_ConfigTypeTemplate *templateVal = NULL;
char *name = malloc(sizeof(char) * subname.length + 1);
strncpy(name, data + subname.index, sizeof(char) * subname.length);
name[subname.length] = '\0';
templateVal = (ARC_ConfigTypeTemplate *) malloc(sizeof(ARC_ConfigTypeTemplate));
templateVal->key = NULL;
templateVal->data = ARC_Config_GetReference(config, data, &subvalue);
if(!templateVal->data){
err = key->Read(config, data, &subvalue, &(templateVal->data));
if(err){ return err; }
templateVal->key = key;
ARC_Hashtable_Get(config->keys, keyType->data, keyType->length, (void **)&key);
if(key == NULL){
arc_errno = ARC_ERRNO_DATA;
}
return ARC_Hashtable_Add(config->currgroup, (void *)name, strlen(name), (void *)templateVal);
if(arc_errno){
return;
}
ARC_ConfigTypeTemplate *templateVal = (ARC_ConfigTypeTemplate *) malloc(sizeof(ARC_ConfigTypeTemplate));
templateVal->Delete = NULL;
uint8_t reference = key->Read(config, value, &(templateVal->data));
if(!reference){
templateVal->Delete = key->Delete;
}
if(arc_errno){
return;
}
char *nameval = (char *)malloc(sizeof(char) * name->length);
strncpy(nameval, name->data, name->length);
ARC_Hashtable_Add(config->currgroup, nameval, name->length, (void *)templateVal);
}
int32_t ARC_ConfigKey_Unload(ARC_Config *config, char *data, uint64_t *size, char *keyname, ARC_StringSubstr *subkey){
ARC_StringSubstr subname = { subkey->index, 0 };
int32_t err = ARC_String_Find(data + subname.index, (char *)"=", &(subname.length));
if(err){ return err; }
if(subname.length == ~((uint64_t)0)){ return ARC_ERRNO_DATA; }
subkey->index += subname.length + 1;
ARC_StringSubstr_StripEnds(data, NULL, &subname);
char name[subname.length + 1];
strncpy(name, data + subname.index, subname.length);
name[subname.length] = '\0';
subname = (ARC_StringSubstr){ subkey->index, 0 };
err = ARC_String_Find(data + subname.index, (char *)";", &(subname.length));
if(err){ return err; }
if(subname.length == ~((uint64_t)0)){ return ARC_ERRNO_DATA; }
subkey->index += subname.length + 1;
return ARC_Config_Remove(config, name, data, &subname);
void ARC_Config_UnloadFromKey(ARC_Config *config, ARC_String *keyType, ARC_String *name){
ARC_Hashtable_Remove(config->currgroup, name->data, name->length, ARC_Config_DestroyGroupNode, &config);
}
int32_t ARC_Config_Recurse(ARC_Config *config, char *data, uint64_t *size, char *groupstr, ARC_StringSubstr *subkey, uint8_t *command){
int32_t err = ARC_Config_SetGroup(config, groupstr);
if(err){ return err; }
void ARC_Config_GetNameAndValue(ARC_String *data, ARC_String **name, ARC_String **value){
uint64_t index = ARC_String_FindCString(data, "=", 1);
if(arc_errno || index == ~(uint64_t)0){
*name = NULL;
*value = NULL;
return;
}
ARC_String_CopySubstring(name, data, 0, index - 1);
index++;
ARC_String *dataTemp = *name;
ARC_String_StripEndsWhitespace(dataTemp, name);
ARC_String_Destroy(dataTemp);
ARC_String_CopySubstring(value, data, index, data->length - index);
}
void ARC_Config_Recurse(ARC_Config *config, ARC_String **data, ARC_String *groupstr, uint8_t *command){
ARC_Config_SetGroup(config, groupstr);
if(arc_errno){
return;
}
ARC_Hashtable *group = config->currgroup;
while(subkey->index < *size){
if(data[subkey->index] == ' ' || data[subkey->index] == '\n' || data[subkey->index] == '\t' || data[subkey->index] == '\r'){
subkey->index++;
continue;
}
while(*data && (*data)->length){
ARC_String *dataTemp = *data;
ARC_String_StripEndsWhitespace(dataTemp, data);
ARC_String_Destroy(dataTemp);
if(data[subkey->index] == '}'){
// break out of current group
if((*data)->data[0] == '}'){
config->currgroup = NULL;
subkey->index++;
return 0;
dataTemp = *data;
ARC_String_CopySubstring(data, dataTemp, 1, dataTemp->length - 1);
ARC_String_Destroy(dataTemp);
return;
}
if(data[subkey->index] == '#'){
err = ARC_ConfigKey_Command(config, data, size, subkey);
if(err){ return err; }
continue;
}
if(data[subkey->index] == '/'){
err = ARC_ConfigKey_Comment(config, data, size, subkey);
if(err){ return err; }
continue;
}
err = ARC_String_Find(data + subkey->index, (char *)" ", &(subkey->length));
if(err){ return err; }
if(subkey->length == ~((uint64_t)0)){ return 0; }
// set group
if(!(config->currgroup)){
config->currgroup = group;
}
char keyname[subkey->length + 1];
strncpy(keyname, data + subkey->index, subkey->length);
keyname[subkey->length] = '\0';
subkey->index += subkey->length + 1;
// get keys type
uint64_t index = ARC_String_FindCString(*data, " ", 1);
if(arc_errno || index == ~(uint64_t)0){
return;
}
ARC_String *keyType, *keyTypeTemp;
ARC_String_CopySubstring(&keyTypeTemp, *data, 0, index);
ARC_String_StripEndsWhitespace(keyTypeTemp, &keyType);
ARC_String_Destroy(keyTypeTemp);
if(ARC_String_EqualsCString(keyType, "group", 5)){
ARC_Config_SetKeyGroup(config, data, command);
if(arc_errno){
ARC_String_Destroy(keyType);
return;
}
if(subkey->length == strlen("group") && !strcmp(keyname, "group")){
err = ARC_ConfigKey_Group(config, data, size, subkey, command);
if(err){ return err; }
continue;
}
// get and copy up to the ;
ARC_String *nameAndValue;
uint64_t nextIndex = ARC_String_FindCString(*data, ";", 1);
if(nextIndex == ~(uint64_t)0){
arc_errno = ARC_ERRNO_DATA;
}
if(arc_errno){
ARC_String_Destroy(keyType);
return;
}
ARC_String_CopySubstring(&nameAndValue, *data, index, nextIndex - (index + 1));
if(arc_errno){
ARC_String_Destroy(keyType);
return;
}
// remove up to the ; from data string
dataTemp = *data;
ARC_String_CopySubstring(data, dataTemp, nextIndex, (*data)->length - nextIndex);
ARC_String_Destroy(dataTemp);
if(arc_errno){
ARC_String_Destroy(keyType);
ARC_String_Destroy(nameAndValue);
return;
}
// get name and value of string
ARC_String *name, *value;
ARC_Config_GetNameAndValue(nameAndValue, &name, &value);
ARC_String_Destroy(nameAndValue);
if(arc_errno){
ARC_String_Destroy(keyType);
return;
}
// load from key
if(*command == ARC_CONFIG_FILE_IO_LOAD){
err = ARC_ConfigKey_Load(config, data, size, keyname, subkey);
if(err){ return err; }
ARC_Config_LoadFromKey(config, keyType, name, value);
if(arc_errno){
ARC_String_Destroy(keyType);
ARC_String_Destroy(name );
ARC_String_Destroy(value );
return;
}
continue;
}
// unload from key
if(*command == ARC_CONFIG_FILE_IO_UNLOAD){
err = ARC_ConfigKey_Unload(config, data, size, keyname, subkey);
if(err){ return err;}
ARC_Config_UnloadFromKey(config, keyType, name);
if(arc_errno){
ARC_String_Destroy(keyType);
ARC_String_Destroy(name );
ARC_String_Destroy(value );
return;
}
continue;
}
return ARC_ERRNO_DATA;
// config file wasn't loaded correctly
ARC_String_Destroy(keyType);
ARC_String_Destroy(name );
ARC_String_Destroy(value );
arc_errno = ARC_ERRNO_DATA;
return;
}
config->currgroup = group;
return 0;
}
int32_t ARC_Config_FileIO(ARC_Config *config, const char *pathstr, uint8_t command){
char *path, *data;
uint64_t size;
ARC_StringSubstr subpath = { 0, strlen(pathstr) };
ARC_ConfigPath_Create((char *)pathstr, &subpath, &path);
void ARC_Config_StripComment(ARC_String *original, ARC_String **stripped, ARC_String *lineStart, ARC_String *lineEnd){
ARC_String *current;
ARC_String_Copy(&current, original);
int32_t err = ARC_IO_FileToStr(path, &data, &size);
if(err){
ARC_DEBUG_LOG(err, "ARC_IO_FileToStr(%s, &data, &size);\n", path);
ARC_ConfigPath_Destroy(path);
return err;
uint64_t index = ARC_String_Find(current, lineStart);
while(index != ~(uint64_t)0){
uint64_t endIndex = ARC_String_Find(current, lineEnd);
if(endIndex == ~(uint64_t)0){
ARC_DEBUG_ERR("ARC_Config_RemoveComments(original, commentRemoved); No newline found when stripping single line comment");
arc_errno = ARC_ERRNO_DATA;
*stripped = NULL;
break;
}
ARC_String *currentTemp = current;
ARC_String_RemoveSection(&current, currentTemp, index, endIndex - index);
ARC_String_Destroy(currentTemp);
index = ARC_String_Find(current, lineStart);
}
ARC_ConfigPath_Destroy(path);
ARC_StringSubstr subkey = { 0, 0 };
err = ARC_Config_Recurse(config, data, &size, "", &subkey, &command);
if(err){ return err; }
free(data);
return 0;
*stripped = current;
}
void *ARC_Config_GetReference(ARC_Config *config, char *data, ARC_StringSubstr *subdata){
if(ARC_String_Alpha(data + subdata->index, 1) && *(data + subdata->index) != ':'){ return NULL; }
void ARC_Config_RemoveComments(ARC_String *original, ARC_String **commentRemoved){
ARC_String *lineStart, *lineEnd;
char refname[subdata->length + 1];
strncpy(refname, data + subdata->index, subdata->length);
refname[subdata->length] = 0;
//Single Line Comment
ARC_String_Create(&lineStart, "//", 2);
ARC_String_Create(&lineEnd , "\n", 1);
void *value;
int32_t err = ARC_Config_Get(config, refname, &value);
return (err)? NULL : value;
ARC_String *singleLineStripped;
ARC_Config_StripComment(original, &singleLineStripped, lineStart, lineEnd);
ARC_String_Destroy(lineStart);
ARC_String_Destroy(lineEnd );
if(arc_errno){
commentRemoved = NULL;
return;
}
//Multi Line Comment
ARC_String_Create(&lineStart, "/*", 2);
ARC_String_Create(&lineEnd , "*/", 2);
ARC_Config_StripComment(singleLineStripped, commentRemoved, lineStart, lineEnd);
ARC_String_Destroy(singleLineStripped);
ARC_String_Destroy(lineStart);
ARC_String_Destroy(lineEnd );
}
void ARC_Config_RunCommand(ARC_Config *config, ARC_String *command){
ARC_String *space;
ARC_String_Create(&space, " " , 1);
uint64_t index = ARC_String_Find(command, space);
if(index == ~(uint64_t)0){
arc_errno = ARC_ERRNO_DATA;
ARC_String_Destroy(space);
return;
}
ARC_String *commandOpt;
ARC_String_CopySubstring(&commandOpt, command, 0, index);
ARC_String *commandArgTemp, *commandArg;
ARC_String_CopySubstring(&commandArgTemp, command, index + space->length, command->length - (index + space->length));
ARC_String_StripWhitespace(commandArgTemp, &commandArg);
ARC_String_Destroy(commandArgTemp);
if(ARC_String_EqualsCString(command, "load", 4)){
ARC_Config_FileIO(config, commandArg, ARC_CONFIG_FILE_IO_LOAD);
}
else if(ARC_String_EqualsCString(command, "unload", 6)){
ARC_Config_FileIO(config, commandArg, ARC_CONFIG_FILE_IO_UNLOAD);
}
else {
arc_errno = ARC_ERRNO_DATA;
}
ARC_String_Destroy(commandOpt);
ARC_String_Destroy(commandArg);
ARC_String_Destroy(space );
}
void ARC_Config_RemoveAndRunCommands(ARC_Config *config, ARC_String *original, ARC_String **commandRemoved){
ARC_String *current;
ARC_String_Copy(&current, original);
ARC_String *lineStart, *lineEnd;
ARC_String_Create(&lineStart, "#" , 1);
ARC_String_Create(&lineEnd , "\n", 1);
uint64_t index = ARC_String_Find(current, lineStart);
while(index != ~(uint64_t)0){
uint64_t endIndex = ARC_String_Find(current, lineEnd);
if(endIndex == ~(uint64_t)0){
arc_errno = ARC_ERRNO_DATA;
ARC_String_Destroy(current );
ARC_String_Destroy(lineStart);
ARC_String_Destroy(lineEnd );
*commandRemoved = NULL;
return;
}
ARC_String *command;
ARC_String_CopySubstring(&command, current, index + lineStart->length, endIndex - (index + lineStart->length));
ARC_Config_RunCommand(config, command);
ARC_String *currentTemp = current;
ARC_String_RemoveSubstring(&current, currentTemp, command);
ARC_String_Destroy(command);
ARC_String_Destroy(currentTemp);
}
ARC_String_Destroy(lineStart);
ARC_String_Destroy(lineEnd );
*commandRemoved = current;
}
void ARC_Config_FileIO(ARC_Config *config, ARC_String *path, uint8_t command){
ARC_String *data;
ARC_IO_FileToStr(path, &data);
if(arc_errno){
ARC_DEBUG_LOG(arc_errno, "ARC_IO_FileToStr(%s, &data, &size);\n", path->data);
return;
}
ARC_String *noCommentData;
ARC_Config_RemoveComments(data, &noCommentData);
ARC_String_Destroy(data);
ARC_String *noCommandData;
ARC_Config_RemoveAndRunCommands(config, noCommentData, &noCommandData);
ARC_String_Destroy(noCommentData);
ARC_Config_Recurse(config, &noCommandData, NULL, &command);
if(noCommandData){
ARC_String_Destroy(noCommandData);
}
}
int8_t ARC_Config_KeyComp(void *key1, size_t *key1size, void *key2, size_t *key2size){
if(*key1size - *key2size){ return -1; }
return strncmp((const char *)key1, (const char *)key2, *key1size);
}
void ARC_Config_CreateGroup(ARC_Config *config, ARC_String *name){
ARC_Hashtable *data;
ARC_Hashtable_Create(&data, ARC_GROUP_DATA_BUCKET_SIZE, NULL, ARC_Config_KeyComp);
if(name){
char *nameval = (char *)malloc(sizeof(char) * name->length);
strncpy(nameval, name->data, name->length);
ARC_Hashtable_Add(config->groups, nameval, name->length, (void *)data);
return;
}
char *emptyGroup = (char *)malloc(sizeof(char));
emptyGroup[0] = ' ';
ARC_Hashtable_Add(config->groups, emptyGroup, 1, (void *)data);
}
void ARC_Config_DestroyGroup(ARC_HashtableNode *group, void *userdata){
free((char *)group->key);
return ARC_Hashtable_Destroy((ARC_Hashtable *)group->data, ARC_Config_DestroyGroupNode, userdata);
}
void ARC_Config_DestroyGroupNode(ARC_HashtableNode *node, void *userdata){
free((char *)node->key);
ARC_ConfigTypeTemplate *temp = (ARC_ConfigTypeTemplate *)node->data;
if(temp->Delete && temp->data && userdata){
ARC_Config *config = (ARC_Config *)userdata;
temp->Delete(config, temp->data);
}
free(temp);
node->data = NULL;
}
void ARC_Config_RemoveKey(ARC_HashtableNode *node, void *userdata){
free((char *)node->key);
if(!node->data){
arc_errno = ARC_ERRNO_NULL;
return;
}
free((ARC_ConfigKey *)node->data);
}