refactored the parser
This commit is contained in:
+16
-2
@@ -7,8 +7,22 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "")
|
||||
# set the project name
|
||||
project(ModManager)
|
||||
|
||||
|
||||
set(SOURCES
|
||||
src/main.c
|
||||
src/steam.c
|
||||
src/install.c
|
||||
src/overlayfs.c
|
||||
src/getHome.c
|
||||
src/file.c
|
||||
src/fomod.c
|
||||
src/fomod/group.c
|
||||
src/fomod/xmlUtil.c
|
||||
src/fomod/parser.c
|
||||
)
|
||||
|
||||
# add the executable
|
||||
add_executable(ModManager src/main.c src/steam.c src/install.c src/overlayfs.c src/getHome.c src/file.c src/fomod.c)
|
||||
add_executable(ModManager ${SOURCES})
|
||||
add_compile_options(-Wall -Wextra -pedantic -Werror)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
@@ -25,4 +39,4 @@ target_link_libraries(ModManager ${GLIB_LDFLAGS})
|
||||
target_link_libraries(ModManager ${LIBXML_LIBRARIES})
|
||||
target_link_libraries(ModManager ${AUDIT_LIBRARIES})
|
||||
|
||||
install(TARGETS ModManager DESTINATION bin)
|
||||
install(TARGETS ModManager DESTINATION bin)
|
||||
|
||||
@@ -44,7 +44,6 @@ int copy(const char * path, const char * dest, u_int32_t flags) {
|
||||
|
||||
args[argIndex] = NULL;
|
||||
|
||||
|
||||
int pid = fork();
|
||||
if(pid == 0) {
|
||||
//discard the const. since we are in a fork we don't care.
|
||||
|
||||
+16
-582
@@ -12,510 +12,7 @@
|
||||
#include <stdarg.h>
|
||||
#include "file.h"
|
||||
#include "libxml/globals.h"
|
||||
|
||||
//replace \ in the path by /
|
||||
void fixPath(char * path) {
|
||||
while(*path != '\0') {
|
||||
if(*path == '\\')*path = '/';
|
||||
path++;
|
||||
}
|
||||
}
|
||||
|
||||
int countUntilNull(void * pointers) {
|
||||
int i = 0;
|
||||
while(pointers != NULL) {
|
||||
pointers++;
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
GroupType_t getGroupType(const char * type) {
|
||||
if(strcmp(type, "SelectAtLeastOne") == 0) {
|
||||
return AT_LEAST_ONE;
|
||||
} else if(strcmp(type, "SelectAtMostOne") == 0) {
|
||||
return AT_MOST_ONE;
|
||||
} else if(strcmp(type, "SelectExactlyOne") == 0) {
|
||||
return ONE_ONLY;
|
||||
} else if(strcmp(type, "SelectAll") == 0) {
|
||||
return ALL;
|
||||
} else if(strcmp(type, "SelectAny") == 0) {
|
||||
return ANY;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
FOModOrder_t getFOModOrder(const char * order) {
|
||||
if(order == NULL || strcmp(order, "Ascending") == 0) {
|
||||
return ASC;
|
||||
} else if(strcmp(order, "Explicit") == 0) {
|
||||
return ORD;
|
||||
} else if(strcmp(order, "Descending") == 0) {
|
||||
return DESC;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
TypeDescriptor_t getDescriptor(const char * descriptor) {
|
||||
if(strcmp(descriptor, "Optional") == 0) {
|
||||
return OPTIONAL;
|
||||
} else if(strcmp(descriptor, "Required") == 0) {
|
||||
return REQUIRED;
|
||||
} else if(strcmp(descriptor, "Recommended") == 0) {
|
||||
return RECOMMENDED;
|
||||
} else if(strcmp(descriptor, "CouldBeUsable") == 0) {
|
||||
return MAYBE_USABLE;
|
||||
} else if(strcmp(descriptor, "NotUsable") == 0) {
|
||||
return NOT_USABLE;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//names cannot contain false
|
||||
//need to be null terminated
|
||||
bool validateNode(xmlNodePtr * node, bool skipText, const char * names, ...) {
|
||||
va_list namesPtr;
|
||||
|
||||
while(*node != NULL && xmlStrcmp((*node)->name, (const xmlChar *)"text") == 0) {
|
||||
if(skipText) {
|
||||
(*node) = (*node)->next;
|
||||
} else {
|
||||
//could not skip and the node was a text node.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(*node == NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
va_start(namesPtr, names);
|
||||
|
||||
const char * validName = names;
|
||||
while(validName != NULL) {
|
||||
if(xmlStrcmp((*node)->name, (const xmlChar *)validName) == 0) {
|
||||
va_end(namesPtr);
|
||||
return true;
|
||||
}
|
||||
validName = va_arg(namesPtr, char *);
|
||||
}
|
||||
|
||||
va_end(namesPtr);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
char * freeAndDup(xmlChar * line) {
|
||||
char * free = strdup((const char *) line);
|
||||
xmlFree(line);
|
||||
return free;
|
||||
}
|
||||
|
||||
int parseGroup(xmlNodePtr groupNode, FOModGroup_t* group) {
|
||||
xmlNodePtr pluginsNode = groupNode->children;
|
||||
if(!validateNode(&pluginsNode, true, "plugins", NULL)) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
group->name = freeAndDup(xmlGetProp( groupNode, (const xmlChar *) "name"));
|
||||
|
||||
xmlChar * type = xmlGetProp(groupNode, (const xmlChar *) "type");
|
||||
group->type = getGroupType((const char *)type);
|
||||
xmlFree(type);
|
||||
|
||||
char * order = (char *) xmlGetProp(pluginsNode, (const xmlChar *) "order");
|
||||
group->order = getFOModOrder(order);
|
||||
xmlFree(order);
|
||||
|
||||
FOModPlugin_t * plugins = NULL;
|
||||
int pluginCount = 0;
|
||||
|
||||
xmlNodePtr currentPlugin = pluginsNode->children;
|
||||
while(currentPlugin != NULL) {
|
||||
if(!validateNode(¤tPlugin, true, "plugin", NULL)) {
|
||||
//TODO handle error;
|
||||
printf("%d\n", __LINE__);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if(currentPlugin == NULL)continue;
|
||||
|
||||
|
||||
pluginCount += 1;
|
||||
plugins = realloc(plugins, pluginCount * sizeof(FOModPlugin_t));
|
||||
FOModPlugin_t * plugin = &plugins[pluginCount - 1];
|
||||
//initialise everything to 0 and null pointers
|
||||
memset(plugin, 0, sizeof(FOModPlugin_t));
|
||||
|
||||
plugin->name = freeAndDup(xmlGetProp(currentPlugin, (const xmlChar *) "name"));
|
||||
|
||||
xmlNodePtr nodeElement = currentPlugin->children;
|
||||
while(nodeElement != NULL) {
|
||||
if(xmlStrcmp(nodeElement->name, (const xmlChar *) "description") == 0) {
|
||||
plugin->description = freeAndDup(xmlNodeGetContent(nodeElement));
|
||||
} else if(xmlStrcmp(nodeElement->name, (const xmlChar *) "image") == 0) {
|
||||
plugin->image = freeAndDup(xmlGetProp(currentPlugin, (const xmlChar *) "path"));
|
||||
} else if(xmlStrcmp(nodeElement->name, (const xmlChar *) "conditionFlags") == 0) {
|
||||
FOModFlag_t * flags = NULL;
|
||||
int flagCount = 0;
|
||||
xmlNodePtr flagNode = nodeElement->children;
|
||||
while(flagNode != NULL) {
|
||||
if(!validateNode(&flagNode, true, "flag", NULL)) {
|
||||
goto failure;
|
||||
}
|
||||
|
||||
if(flagNode == NULL)continue;
|
||||
|
||||
flagCount += 1;
|
||||
flags = realloc(flags, flagCount * sizeof(FOModFlag_t));
|
||||
|
||||
flags[flagCount - 1].name = freeAndDup(xmlGetProp(flagNode, (const xmlChar *) "name"));
|
||||
flags[flagCount - 1].value = freeAndDup(xmlNodeGetContent(flagNode));
|
||||
|
||||
flagNode = flagNode->next;
|
||||
}
|
||||
plugin->flags = flags;
|
||||
plugin->flagCount = flagCount;
|
||||
} else if(xmlStrcmp(nodeElement->name, (const xmlChar *) "files") == 0) {
|
||||
FOModFile_t * files = NULL;
|
||||
xmlNodePtr fileNode = nodeElement->children;
|
||||
while(fileNode != NULL) {
|
||||
if(!validateNode(&fileNode, true, "folder", "file", NULL)) {
|
||||
fprintf(stderr, "Unexpected node in files");
|
||||
goto failure;
|
||||
}
|
||||
|
||||
if(fileNode == NULL)continue;
|
||||
|
||||
plugin->fileCount += 1;
|
||||
|
||||
plugin->files = realloc(plugin->files, (plugin->fileCount + 1) * sizeof(FOModFile_t));
|
||||
FOModFile_t * file = &plugin->files[plugin->fileCount - 1];
|
||||
|
||||
file->destination = freeAndDup(xmlGetProp(fileNode, (const xmlChar *) "destination"));
|
||||
file->source = freeAndDup(xmlGetProp(fileNode, (const xmlChar *) "source"));
|
||||
|
||||
//TODO: test if it's a number
|
||||
xmlChar * priority = xmlGetProp(fileNode, (const xmlChar *) "priority");
|
||||
if(priority == NULL) {
|
||||
file->priority = 0;
|
||||
} else {
|
||||
file->priority = atoi((char *)priority);
|
||||
}
|
||||
xmlFree(priority);
|
||||
file->isFolder = xmlStrcmp(fileNode->name, (const xmlChar *) "folder") == 0;
|
||||
|
||||
fileNode = fileNode->next;
|
||||
}
|
||||
} else if(xmlStrcmp(nodeElement->name, (const xmlChar *) "typeDescriptor") == 0) {
|
||||
xmlNodePtr typeNode = nodeElement->children;
|
||||
if(!validateNode(&typeNode, true, "type", NULL)) {
|
||||
fprintf(stderr, "Unexpected node in typeDescriptor");
|
||||
goto failure;
|
||||
}
|
||||
xmlChar * name = xmlGetProp(typeNode, (const xmlChar *) "name");
|
||||
plugin->type = getDescriptor((char *) name);
|
||||
xmlFree(name);
|
||||
}
|
||||
|
||||
nodeElement = nodeElement->next;
|
||||
}
|
||||
|
||||
|
||||
currentPlugin = currentPlugin->next;
|
||||
}
|
||||
|
||||
group->plugins = plugins;
|
||||
group->pluginCount = pluginCount;
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
failure:
|
||||
//we need to free all of our allocations since we can't expect ou parent function to know what we allocated and what we haven't.
|
||||
if(pluginCount != 0) {
|
||||
for(int pluginId = 0; pluginId < pluginCount; pluginId++) {
|
||||
FOModPlugin_t * plugin = &plugins[pluginId];
|
||||
if(plugin->fileCount != 0) {
|
||||
for(int i = 0; i < plugin->fileCount; i++) {
|
||||
free(plugin->files[i].destination);
|
||||
free(plugin->files[i].source);
|
||||
}
|
||||
free(plugin->files);
|
||||
}
|
||||
|
||||
if(plugin->flagCount != 0) {
|
||||
for(int i = 0; i < plugin->flagCount; i++) {
|
||||
free(plugin->flags[i].name);
|
||||
free(plugin->flags[i].value);
|
||||
}
|
||||
free(plugin->flags);
|
||||
}
|
||||
|
||||
if(plugin->description != NULL)free(plugin->description);
|
||||
if(plugin->image != NULL)free(plugin->image);
|
||||
if(plugin->name != NULL)free(plugin->name);
|
||||
}
|
||||
free(plugins);
|
||||
}
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
FOModStep_t * parseInstallSteps(xmlNodePtr installStepsNode, int * stepCount) {
|
||||
FOModStep_t * steps = NULL;
|
||||
*stepCount = 0;
|
||||
|
||||
xmlNodePtr stepNode = installStepsNode->children;
|
||||
while(stepNode != NULL) {
|
||||
//skipping the text node
|
||||
if(!validateNode(&stepNode, true, "installStep", NULL)) {
|
||||
//TODO: handle error
|
||||
printf("%d\n", __LINE__);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if(stepNode == NULL)break;
|
||||
|
||||
*stepCount += 1;
|
||||
steps = realloc(steps, *stepCount * sizeof(FOModStep_t));
|
||||
|
||||
FOModStep_t * step = &steps[*stepCount - 1];
|
||||
step->name = freeAndDup(xmlGetProp(stepNode, (const xmlChar *)"name"));
|
||||
step->requiredFlags = NULL;
|
||||
step->flagCount = 0;
|
||||
step->groupCount = 0;
|
||||
step->groups = NULL;
|
||||
|
||||
xmlNodePtr stepchildren = stepNode->children;
|
||||
|
||||
while(stepchildren != NULL) {
|
||||
if(xmlStrcmp(stepchildren->name, (const xmlChar *) "visible") == 0) {
|
||||
xmlNodePtr requiredFlagsNode = stepchildren->children;
|
||||
|
||||
while (requiredFlagsNode != NULL) {
|
||||
|
||||
if(!validateNode(&requiredFlagsNode, true, "flagDependency", NULL)) {
|
||||
//TODO: handle error
|
||||
printf("%d\n", __LINE__);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if(requiredFlagsNode == NULL)break;
|
||||
|
||||
step->flagCount += 1;
|
||||
step->requiredFlags = realloc(step->requiredFlags, step->flagCount * sizeof(FOModFlag_t));
|
||||
FOModFlag_t * flag = &(step->requiredFlags[step->flagCount - 1]);
|
||||
flag->name = freeAndDup(xmlGetProp(requiredFlagsNode, (const xmlChar *) "flag"));
|
||||
flag->value = freeAndDup(xmlGetProp(requiredFlagsNode, (const xmlChar *) "value"));
|
||||
|
||||
requiredFlagsNode = requiredFlagsNode->next;
|
||||
}
|
||||
|
||||
} else if(xmlStrcmp(stepchildren->name, (const xmlChar *) "optionalFileGroups") == 0) {
|
||||
|
||||
xmlChar * optionOrder = xmlGetProp(stepchildren, (const xmlChar *)"order");
|
||||
step->optionOrder = getFOModOrder((char *)optionOrder);
|
||||
xmlFree(optionOrder);
|
||||
//skipping the text node;
|
||||
xmlNodePtr group = stepchildren->children;
|
||||
while(group != NULL) {
|
||||
if(!validateNode(&group, true, "group", NULL)) {
|
||||
//TODO: handle error
|
||||
printf("%d\n", __LINE__);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if(group == NULL)break;
|
||||
|
||||
step->groupCount += 1;
|
||||
step->groups = realloc(step->groups, step->groupCount * sizeof(FOModGroup_t));
|
||||
int status = parseGroup(group, &step->groups[step->groupCount - 1]);
|
||||
|
||||
if(status != EXIT_SUCCESS) {
|
||||
//TODO: handle error
|
||||
}
|
||||
|
||||
group = group->next;
|
||||
}
|
||||
}
|
||||
|
||||
stepchildren = stepchildren->next;
|
||||
}
|
||||
|
||||
|
||||
|
||||
stepNode = stepNode->next;
|
||||
}
|
||||
return steps;
|
||||
}
|
||||
|
||||
int parseFOMod(const char * fomodFile, FOMod_t* fomod) {
|
||||
xmlDocPtr doc;
|
||||
xmlNodePtr cur;
|
||||
|
||||
fomod->condFiles = NULL;
|
||||
fomod->condFilesCount = 0;
|
||||
fomod->requiredInstallFiles = NULL;
|
||||
fomod->stepCount = 0;
|
||||
fomod->stepOrder = 0;
|
||||
fomod->steps = NULL;
|
||||
fomod->moduleImage = NULL;
|
||||
fomod->moduleName = NULL;
|
||||
|
||||
doc = xmlParseFile(fomodFile);
|
||||
|
||||
if(doc == NULL) {
|
||||
fprintf(stderr, "Document is not a valid xml file\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
cur = xmlDocGetRootElement(doc);
|
||||
if(cur == NULL) {
|
||||
fprintf(stderr, "emptyDocument");
|
||||
xmlFreeDoc(doc);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if(xmlStrcmp(cur->name, (const xmlChar *) "config") != 0) {
|
||||
fprintf(stderr, "document of the wrong type, root node is '%s' instead of config\n", cur->name);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
cur = cur->children;
|
||||
while(cur != NULL) {
|
||||
if(xmlStrcmp(cur->name, (const xmlChar *) "moduleName") == 0) {
|
||||
//might cause some issues. when will c finally support utf-8
|
||||
fomod->moduleName = (char *)cur->content;
|
||||
} else if(xmlStrcmp(cur->name, (const xmlChar *) "moduleImage") == 0) {
|
||||
fomod->moduleImage = freeAndDup(xmlGetProp(cur, (const xmlChar *)"path"));
|
||||
} else if(xmlStrcmp(cur->name, (const xmlChar *)"requiredInstallFiles") == 0) {
|
||||
//TODO: support non empty destination.
|
||||
xmlNodePtr requiredInstallFile = cur->children;
|
||||
while(requiredInstallFile != NULL) {
|
||||
if(validateNode(&requiredInstallFile, true, "folder", "file", NULL)) {
|
||||
//TODO: handle error
|
||||
printf("%d\n", __LINE__);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int size = countUntilNull(fomod->requiredInstallFiles) + 2;
|
||||
fomod->requiredInstallFiles = realloc(fomod->requiredInstallFiles, sizeof(char *) * size);
|
||||
//ensure it is null terminated
|
||||
fomod->requiredInstallFiles[size - 1] = NULL;
|
||||
fomod->requiredInstallFiles[size - 2] = freeAndDup(xmlGetProp(requiredInstallFile, (const xmlChar *)"source"));
|
||||
|
||||
requiredInstallFile = cur->children;
|
||||
}
|
||||
} else if(xmlStrcmp(cur->name, (const xmlChar *)"installSteps") == 0) {
|
||||
if(fomod->steps != NULL) {
|
||||
fprintf(stderr, "Multiple 'installSteps' tags");
|
||||
//TODO: handle error
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
xmlChar * stepOrder = xmlGetProp(cur, (xmlChar *)"order");
|
||||
fomod->stepOrder = getFOModOrder((char *)stepOrder);
|
||||
xmlFree(stepOrder);
|
||||
|
||||
int stepCount = 0;
|
||||
FOModStep_t * steps = parseInstallSteps(cur, &stepCount);
|
||||
|
||||
if(steps == NULL) {
|
||||
fprintf(stderr, "Failed to parse the install steps\n");
|
||||
|
||||
//TODO: manage the error properly
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
fomod->steps = steps;
|
||||
fomod->stepCount = stepCount;
|
||||
} else if(xmlStrcmp(cur->name, (const xmlChar *) "conditionalFileInstalls") == 0) {
|
||||
xmlNodePtr patterns = cur->children;
|
||||
if(patterns != NULL) {
|
||||
if(!validateNode(&patterns, true, "patterns", NULL)) {
|
||||
//TODO: handle error
|
||||
printf("%d\n", __LINE__);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
xmlNodePtr currentPattern = patterns->children;
|
||||
while(currentPattern != NULL) {
|
||||
xmlNodePtr patternChild = currentPattern->children;
|
||||
|
||||
if(!validateNode(&patternChild, true, "pattern", NULL)) {
|
||||
//TODO: handle error
|
||||
printf("%d\n", __LINE__);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
while(patternChild != NULL) {
|
||||
fomod->condFilesCount += 1;
|
||||
fomod->condFiles = realloc(fomod->condFiles, fomod->condFilesCount * sizeof(FOModCondFile_t));
|
||||
FOModCondFile_t * condFile = &(fomod->condFiles[fomod->condFilesCount - 1]);
|
||||
|
||||
condFile->fileCount = 0;
|
||||
condFile->files = NULL;
|
||||
condFile->flagCount = 0;
|
||||
condFile->requiredFlags = NULL;
|
||||
|
||||
if(xmlStrcmp(patternChild->name, (xmlChar *)"dependencies") == 0) {
|
||||
xmlNodePtr flagNode = patternChild->children;
|
||||
|
||||
if(!validateNode(&flagNode, true, "flagDependency", NULL)) {
|
||||
//TODO: handle error
|
||||
printf("%d\n", __LINE__);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
while(flagNode != NULL) {
|
||||
condFile->flagCount += 1;
|
||||
condFile->requiredFlags = realloc(condFile->requiredFlags, condFile->flagCount * sizeof(FOModFlag_t));
|
||||
FOModFlag_t * flag = &(condFile->requiredFlags[condFile->flagCount - 1]);
|
||||
flag->name = freeAndDup(xmlGetProp(flagNode, (const xmlChar *) "flag"));
|
||||
flag->value = freeAndDup(xmlGetProp(flagNode, (const xmlChar *) "value"));
|
||||
|
||||
flagNode = flagNode->next;
|
||||
}
|
||||
|
||||
|
||||
} else if(xmlStrcmp(patternChild->name, (xmlChar *)"files") == 0) {
|
||||
xmlNodePtr filesNode = patternChild->children;
|
||||
|
||||
|
||||
while(filesNode != NULL) {
|
||||
if(!validateNode(&filesNode, true, "folder", "file", NULL)) {
|
||||
//TODO: handle error
|
||||
printf("%d\n", __LINE__);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
condFile->fileCount += 1;
|
||||
condFile->files = realloc(condFile->files, condFile->fileCount * sizeof(FOModFile_t));
|
||||
FOModFile_t * flag = &(condFile->files[condFile->fileCount - 1]);
|
||||
flag->source = freeAndDup(xmlGetProp(filesNode, (const xmlChar *) "source"));
|
||||
flag->destination = freeAndDup(xmlGetProp(filesNode, (const xmlChar *) "destination"));
|
||||
flag->priority = 0;
|
||||
flag->isFolder = xmlStrcmp(patternChild->name, (xmlChar *) "folder") == 0;
|
||||
|
||||
filesNode = filesNode->next;
|
||||
}
|
||||
}
|
||||
patternChild = patternChild->next;
|
||||
}
|
||||
currentPattern = currentPattern->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
xmlFreeDoc(doc);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
#include "fomod/parser.h"
|
||||
|
||||
int getInputCount(const char * input) {
|
||||
char buff[2];
|
||||
@@ -524,7 +21,7 @@ int getInputCount(const char * input) {
|
||||
int elementCount = 0;
|
||||
bool prevWasValue = false;
|
||||
|
||||
for(int i = 0; input[i] != '\0' && input[i] != '\n'; i++) {
|
||||
for(int i = 0; input + i != NULL && input[i] != '\0' && input[i] != '\n'; i++) {
|
||||
buff[0] = input[i];
|
||||
|
||||
//if the character is a valid character
|
||||
@@ -602,69 +99,6 @@ gint flagEqual(const FOModFlag_t * a, const FOModFlag_t * b) {
|
||||
return nameCmp;
|
||||
}
|
||||
|
||||
//Maybe integrate this into the rest of the code instead of freeing after the fact
|
||||
void freeFOMod(FOMod_t * fomod) {
|
||||
for(int i = 0; i < fomod->condFilesCount; i++) {
|
||||
FOModCondFile_t * condFile = &(fomod->condFiles[i]);
|
||||
for(int fileId = 0; fileId < condFile->fileCount; fileId++) {
|
||||
free(condFile->files[fileId].destination);
|
||||
free(condFile->files[fileId].source);
|
||||
}
|
||||
|
||||
for(int flagId = 0; flagId < condFile->flagCount; flagId++) {
|
||||
FOModFlag_t * flag = &(condFile->requiredFlags[flagId]);
|
||||
free(flag->name);
|
||||
free(flag->value);
|
||||
}
|
||||
free(condFile->files);
|
||||
free(condFile->requiredFlags);
|
||||
}
|
||||
free(fomod->condFiles);
|
||||
|
||||
free(fomod->moduleImage);
|
||||
free(fomod->moduleName);
|
||||
|
||||
int size = countUntilNull(fomod->requiredInstallFiles);
|
||||
for(int i = 0; i < size; i++) {
|
||||
free(fomod->requiredInstallFiles[i]);
|
||||
}
|
||||
free(fomod->requiredInstallFiles);
|
||||
|
||||
for(int i = 0; i < fomod->stepCount; i++) {
|
||||
FOModStep_t * step = &fomod->steps[i];
|
||||
for(int groupId = 0; groupId < step->groupCount; groupId++) {
|
||||
FOModGroup_t * group = &step->groups[groupId];
|
||||
free(group->name);
|
||||
for(int pluginId = 0; pluginId < group->pluginCount; pluginId++) {
|
||||
FOModPlugin_t * plugin = &(group->plugins[pluginId]);
|
||||
free(plugin->description);
|
||||
free(plugin->image);
|
||||
free(plugin->name);
|
||||
for(int fileId = 0; fileId < plugin->fileCount; fileId++) {
|
||||
free(plugin->files[fileId].destination);
|
||||
free(plugin->files[fileId].source);
|
||||
}
|
||||
|
||||
for(int flagId = 0; flagId < plugin->flagCount; flagId++) {
|
||||
free(plugin->flags[flagId].name);
|
||||
free(plugin->flags[flagId].value);
|
||||
}
|
||||
|
||||
free(plugin->files);
|
||||
free(plugin->flags);
|
||||
}
|
||||
free(step->groups[groupId].plugins);
|
||||
}
|
||||
for(int flagId = 0; flagId < step->flagCount; flagId++) {
|
||||
FOModFlag_t * flag = &(step->requiredFlags[flagId]);
|
||||
free(flag->name);
|
||||
free(flag->value);
|
||||
}
|
||||
free(step->requiredFlags);
|
||||
free(step->name);
|
||||
}
|
||||
}
|
||||
|
||||
int stepCmpAsc(const void * stepA, const void * stepB) {
|
||||
const FOModStep_t * step1 = (const FOModStep_t *)stepA;
|
||||
const FOModStep_t * step2 = (const FOModStep_t *)stepB;
|
||||
@@ -748,8 +182,8 @@ int installFOMod(const char * modFolder, const char * destination) {
|
||||
FOModStep_t * step = &fomod.steps[i];
|
||||
|
||||
bool validFlags = true;
|
||||
for(int i = 0; i < step->flagCount; i++) {
|
||||
GList * flagLink = g_list_find_custom(flagList, &step->requiredFlags[i], (GCompareFunc)flagEqual);
|
||||
for(int flagId = 0; flagId < step->flagCount; flagId++) {
|
||||
const GList * flagLink = g_list_find_custom(flagList, &step->requiredFlags[flagId], (GCompareFunc)flagEqual);
|
||||
if(flagLink == NULL) {
|
||||
validFlags = false;
|
||||
break;
|
||||
@@ -781,13 +215,13 @@ int installFOMod(const char * modFolder, const char * destination) {
|
||||
case ANY:
|
||||
printf("Select any (space separated) (leave empty for nothing) :\n");
|
||||
min = 0;
|
||||
max = group.pluginCount - 1;
|
||||
max = (u_int8_t)group.pluginCount - 1;
|
||||
break;
|
||||
|
||||
case AT_LEAST_ONE:
|
||||
printf("Select at least one (space separated) (leave empty for nothing) :\n");
|
||||
min = 1;
|
||||
max = group.pluginCount - 1;
|
||||
max = (u_int8_t)group.pluginCount - 1;
|
||||
break;
|
||||
|
||||
case AT_MOST_ONE:
|
||||
@@ -826,13 +260,13 @@ int installFOMod(const char * modFolder, const char * destination) {
|
||||
for(int choiceId = 0; choices[choiceId] != NULL; choiceId++) {
|
||||
int choice = atoi(choices[choiceId]);
|
||||
FOModPlugin_t plugin = group.plugins[choice];
|
||||
for(int i = 0; i < plugin.flagCount; i++) {
|
||||
flagList = g_list_append(flagList, &plugin.flags[i]);
|
||||
for(int flagId = 0; flagId < plugin.flagCount; flagId++) {
|
||||
flagList = g_list_append(flagList, &plugin.flags[flagId]);
|
||||
}
|
||||
|
||||
//do the install
|
||||
for(int i = 0; i < plugin.fileCount; i++) {
|
||||
FOModFile_t * file = &plugin.files[i];
|
||||
for(int pluginId = 0; pluginId < plugin.fileCount; pluginId++) {
|
||||
const FOModFile_t * file = &plugin.files[pluginId];
|
||||
|
||||
FOModFile_t * fileCopy = malloc(sizeof(*file));
|
||||
*fileCopy = *file;
|
||||
@@ -847,13 +281,13 @@ int installFOMod(const char * modFolder, const char * destination) {
|
||||
}
|
||||
|
||||
for(int condId = 0; condId < fomod.condFilesCount; condId++) {
|
||||
FOModCondFile_t *condfile = &fomod.condFiles[condId];
|
||||
const FOModCondFile_t *condFile = &fomod.condFiles[condId];
|
||||
|
||||
bool areAllFlagsValid = true;
|
||||
|
||||
//check if all flags are valid;
|
||||
for(int flagId = 0; flagId < condfile->flagCount; flagId++) {
|
||||
GList * link = g_list_find_custom(flagList, &(condfile->requiredFlags[flagId]), (GCompareFunc)flagEqual);
|
||||
//checking if all flags are valid
|
||||
for(int flagId = 0; flagId < condFile->flagCount; flagId++) {
|
||||
const GList * link = g_list_find_custom(flagList, &(condFile->requiredFlags[flagId]), (GCompareFunc)flagEqual);
|
||||
if(link == NULL) {
|
||||
areAllFlagsValid = false;
|
||||
break;
|
||||
@@ -861,8 +295,8 @@ int installFOMod(const char * modFolder, const char * destination) {
|
||||
}
|
||||
|
||||
if(areAllFlagsValid) {
|
||||
for(int fileId = 0; fileId < condfile->flagCount; fileId++) {
|
||||
FOModFile_t * file = &(condfile->files[fileId]);
|
||||
for(int fileId = 0; fileId < condFile->flagCount; fileId++) {
|
||||
const FOModFile_t * file = &(condFile->files[fileId]);
|
||||
|
||||
FOModFile_t * fileCopy = malloc(sizeof(*file));
|
||||
*fileCopy = *file;
|
||||
|
||||
+2
-64
@@ -2,70 +2,8 @@
|
||||
#define __FOMOD_H__
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
typedef enum FOModOrder { ASC, DESC, ORD } FOModOrder_t;
|
||||
typedef enum GroupType_t { ONE_ONLY, ANY, AT_LEAST_ONE, AT_MOST_ONE, ALL } GroupType_t;
|
||||
typedef enum TypeDescriptor { OPTIONAL, MAYBE_USABLE, NOT_USABLE, REQUIRED, RECOMMENDED } TypeDescriptor_t;
|
||||
|
||||
typedef struct FOModFlag {
|
||||
char * name;
|
||||
char * value;
|
||||
} FOModFlag_t;
|
||||
|
||||
typedef struct FOModFile {
|
||||
char * source;
|
||||
char * destination;
|
||||
int priority;
|
||||
bool isFolder;
|
||||
} FOModFile_t;
|
||||
|
||||
typedef struct FOModPlugin {
|
||||
char * description;
|
||||
char * image;
|
||||
FOModFlag_t * flags;
|
||||
int flagCount;
|
||||
FOModFile_t * files;
|
||||
int fileCount;
|
||||
TypeDescriptor_t type;
|
||||
char * name;
|
||||
} FOModPlugin_t;
|
||||
|
||||
//combine group and plugins
|
||||
typedef struct FOModGroup {
|
||||
FOModPlugin_t * plugins;
|
||||
int pluginCount;
|
||||
GroupType_t type;
|
||||
char * name;
|
||||
FOModOrder_t order;
|
||||
} FOModGroup_t;
|
||||
|
||||
//combine installStep and optionalFileGroups
|
||||
typedef struct FOModStep {
|
||||
FOModOrder_t optionOrder;
|
||||
FOModGroup_t * groups;
|
||||
int groupCount;
|
||||
char * name;
|
||||
FOModFlag_t * requiredFlags;
|
||||
int flagCount;
|
||||
} FOModStep_t;
|
||||
|
||||
typedef struct FOModCondFile {
|
||||
FOModFlag_t * requiredFlags;
|
||||
unsigned int flagCount;
|
||||
FOModFile_t * files;
|
||||
unsigned int fileCount;
|
||||
} FOModCondFile_t;
|
||||
|
||||
typedef struct FOMod {
|
||||
char * moduleName;
|
||||
char * moduleImage;
|
||||
char ** requiredInstallFiles;
|
||||
FOModOrder_t stepOrder;
|
||||
FOModStep_t * steps;
|
||||
int stepCount;
|
||||
FOModCondFile_t * condFiles;
|
||||
int condFilesCount;
|
||||
} FOMod_t;
|
||||
#include "fomod/group.h"
|
||||
#include "fomod/xmlUtil.h"
|
||||
|
||||
int installFOMod(const char * modFolder, const char * destination);
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
#ifndef __FOMOD_TYPES_H__
|
||||
#define __FOMOD_TYPES_H__
|
||||
|
||||
#include "stdbool.h"
|
||||
#include "xmlUtil.h"
|
||||
|
||||
typedef struct FOModFlag {
|
||||
char * name;
|
||||
char * value;
|
||||
} FOModFlag_t;
|
||||
|
||||
typedef struct FOModFile {
|
||||
char * source;
|
||||
char * destination;
|
||||
int priority;
|
||||
bool isFolder;
|
||||
} FOModFile_t;
|
||||
|
||||
|
||||
|
||||
typedef struct FOModCondFile {
|
||||
FOModFlag_t * requiredFlags;
|
||||
unsigned int flagCount;
|
||||
FOModFile_t * files;
|
||||
unsigned int fileCount;
|
||||
} FOModCondFile_t;
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,208 @@
|
||||
#include "group.h"
|
||||
#include "xmlUtil.h"
|
||||
#include "string.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
GroupType_t getGroupType(const char * type) {
|
||||
if(strcmp(type, "SelectAtLeastOne") == 0) {
|
||||
return AT_LEAST_ONE;
|
||||
} else if(strcmp(type, "SelectAtMostOne") == 0) {
|
||||
return AT_MOST_ONE;
|
||||
} else if(strcmp(type, "SelectExactlyOne") == 0) {
|
||||
return ONE_ONLY;
|
||||
} else if(strcmp(type, "SelectAll") == 0) {
|
||||
return ALL;
|
||||
} else if(strcmp(type, "SelectAny") == 0) {
|
||||
return ANY;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
TypeDescriptor_t getDescriptor(const char * descriptor) {
|
||||
if(strcmp(descriptor, "Optional") == 0) {
|
||||
return OPTIONAL;
|
||||
} else if(strcmp(descriptor, "Required") == 0) {
|
||||
return REQUIRED;
|
||||
} else if(strcmp(descriptor, "Recommended") == 0) {
|
||||
return RECOMMENDED;
|
||||
} else if(strcmp(descriptor, "CouldBeUsable") == 0) {
|
||||
return MAYBE_USABLE;
|
||||
} else if(strcmp(descriptor, "NotUsable") == 0) {
|
||||
return NOT_USABLE;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void freeGroup(FOModGroup_t * group) {
|
||||
if(group->pluginCount == 0) return;
|
||||
for(int pluginId = 0; pluginId < group->pluginCount; pluginId++) {
|
||||
FOModPlugin_t * plugin = &group->plugins[pluginId];
|
||||
if(plugin->fileCount > 0) {
|
||||
for(int i = 0; i < plugin->fileCount; i++) {
|
||||
free(plugin->files[i].destination);
|
||||
free(plugin->files[i].source);
|
||||
}
|
||||
free(plugin->files);
|
||||
}
|
||||
|
||||
if(plugin->flagCount > 0) {
|
||||
for(int i = 0; i < plugin->flagCount; i++) {
|
||||
free(plugin->flags[i].value);
|
||||
free(plugin->flags[i].name);
|
||||
}
|
||||
free(plugin->flags);
|
||||
}
|
||||
|
||||
if(plugin->description != NULL)free(plugin->description);
|
||||
if(plugin->image != NULL)free(plugin->image);
|
||||
if(plugin->name != NULL)free(plugin->name);
|
||||
}
|
||||
free(group->plugins);
|
||||
group->plugins = NULL;
|
||||
group->pluginCount = 0;
|
||||
}
|
||||
|
||||
int parseConditionFlags(FOModPlugin_t * plugin, xmlNodePtr nodeElement) {
|
||||
xmlNodePtr flagNode = nodeElement->children;
|
||||
while(flagNode != NULL) {
|
||||
if(!validateNode(&flagNode, true, "flag", NULL)) {
|
||||
if(plugin->flagCount > 0) {
|
||||
free(plugin->flags);
|
||||
}
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
if(flagNode == NULL)continue;
|
||||
|
||||
plugin->flagCount += 1;
|
||||
plugin->flags = realloc(plugin->flags, plugin->flagCount * sizeof(FOModFlag_t));
|
||||
|
||||
FOModFlag_t * flag = &plugin->flags[plugin->flagCount - 1];
|
||||
|
||||
flag->name = freeAndDup(xmlGetProp(flagNode, (const xmlChar *) "name"));
|
||||
flag->value = freeAndDup(xmlNodeGetContent(flagNode));
|
||||
|
||||
flagNode = flagNode->next;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int parseGroupFiles(FOModPlugin_t * plugin, xmlNodePtr nodeElement) {
|
||||
FOModFile_t * files = NULL;
|
||||
xmlNodePtr fileNode = nodeElement->children;
|
||||
while(fileNode != NULL) {
|
||||
if(!validateNode(&fileNode, true, "folder", "file", NULL)) {
|
||||
fprintf(stderr, "Unexpected node in files");
|
||||
//TODO: free
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if(fileNode == NULL)continue;
|
||||
|
||||
plugin->fileCount += 1;
|
||||
|
||||
plugin->files = realloc(plugin->files, (plugin->fileCount + 1) * sizeof(FOModFile_t));
|
||||
FOModFile_t * file = &plugin->files[plugin->fileCount - 1];
|
||||
|
||||
file->destination = freeAndDup(xmlGetProp(fileNode, (const xmlChar *) "destination"));
|
||||
file->source = freeAndDup(xmlGetProp(fileNode, (const xmlChar *) "source"));
|
||||
|
||||
//TODO: test if it's a number
|
||||
xmlChar * priority = xmlGetProp(fileNode, (const xmlChar *) "priority");
|
||||
if(priority == NULL) {
|
||||
file->priority = 0;
|
||||
} else {
|
||||
file->priority = atoi((char *)priority);
|
||||
}
|
||||
xmlFree(priority);
|
||||
file->isFolder = xmlStrcmp(fileNode->name, (const xmlChar *) "folder") == 0;
|
||||
fileNode = fileNode->next;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int parseNodeElement(FOModPlugin_t * plugin, xmlNodePtr nodeElement) {
|
||||
if(xmlStrcmp(nodeElement->name, (const xmlChar *) "description") == 0) {
|
||||
plugin->description = freeAndDup(xmlNodeGetContent(nodeElement));
|
||||
} else if(xmlStrcmp(nodeElement->name, (const xmlChar *) "image") == 0) {
|
||||
plugin->image = freeAndDup(xmlGetProp(nodeElement, (const xmlChar *) "path"));
|
||||
} else if(xmlStrcmp(nodeElement->name, (const xmlChar *) "conditionFlags") == 0) {
|
||||
return parseConditionFlags(plugin, nodeElement);
|
||||
} else if(xmlStrcmp(nodeElement->name, (const xmlChar *) "files") == 0) {
|
||||
return parseGroupFiles(plugin, nodeElement);
|
||||
} else if(xmlStrcmp(nodeElement->name, (const xmlChar *) "typeDescriptor") == 0) {
|
||||
xmlNodePtr typeNode = nodeElement->children;
|
||||
if(!validateNode(&typeNode, true, "type", NULL)) {
|
||||
fprintf(stderr, "Unexpected node in typeDescriptor");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
xmlChar * name = xmlGetProp(typeNode, (const xmlChar *) "name");
|
||||
plugin->type = getDescriptor((char *) name);
|
||||
xmlFree(name);
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int parseGroup(xmlNodePtr groupNode, FOModGroup_t* group) {
|
||||
xmlNodePtr pluginsNode = groupNode->children;
|
||||
if(!validateNode(&pluginsNode, true, "plugins", NULL)) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
group->name = freeAndDup(xmlGetProp( groupNode, (const xmlChar *) "name"));
|
||||
|
||||
xmlChar * type = xmlGetProp(groupNode, (const xmlChar *) "type");
|
||||
group->type = getGroupType((const char *)type);
|
||||
xmlFree(type);
|
||||
|
||||
char * order = (char *) xmlGetProp(pluginsNode, (const xmlChar *) "order");
|
||||
group->order = getFOModOrder(order);
|
||||
xmlFree(order);
|
||||
|
||||
FOModPlugin_t * plugins = NULL;
|
||||
int pluginCount = 0;
|
||||
|
||||
xmlNodePtr currentPlugin = pluginsNode->children;
|
||||
while(currentPlugin != NULL) {
|
||||
if(!validateNode(¤tPlugin, true, "plugin", NULL)) {
|
||||
//TODO handle error;
|
||||
printf("%d\n", __LINE__);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if(currentPlugin == NULL)continue;
|
||||
|
||||
|
||||
pluginCount += 1;
|
||||
plugins = realloc(plugins, pluginCount * sizeof(FOModPlugin_t));
|
||||
FOModPlugin_t * plugin = &plugins[pluginCount - 1];
|
||||
//initialise everything to 0 and null pointers
|
||||
memset(plugin, 0, sizeof(FOModPlugin_t));
|
||||
|
||||
plugin->name = freeAndDup(xmlGetProp(currentPlugin, (const xmlChar *) "name"));
|
||||
|
||||
xmlNodePtr nodeElement = currentPlugin->children;
|
||||
while(nodeElement != NULL) {
|
||||
if(parseNodeElement(plugin, nodeElement) != EXIT_SUCCESS)
|
||||
goto failure;
|
||||
nodeElement = nodeElement->next;
|
||||
}
|
||||
|
||||
|
||||
currentPlugin = currentPlugin->next;
|
||||
}
|
||||
|
||||
group->plugins = plugins;
|
||||
group->pluginCount = pluginCount;
|
||||
return EXIT_SUCCESS;
|
||||
|
||||
failure:
|
||||
//we need to free all of our allocations since we can't expect ou parent function to know what we allocated and what we haven't.
|
||||
group->plugins = plugins;
|
||||
group->pluginCount = pluginCount;
|
||||
freeGroup(group);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
#ifndef __GROUP_H__
|
||||
#define __GROUP_H__
|
||||
|
||||
#include <libxml/parser.h>
|
||||
#include "fomodTypes.h"
|
||||
|
||||
typedef enum GroupType_t { ONE_ONLY, ANY, AT_LEAST_ONE, AT_MOST_ONE, ALL } GroupType_t;
|
||||
typedef enum TypeDescriptor { OPTIONAL, MAYBE_USABLE, NOT_USABLE, REQUIRED, RECOMMENDED } TypeDescriptor_t;
|
||||
|
||||
typedef struct FOModPlugin {
|
||||
char * description;
|
||||
char * image;
|
||||
FOModFlag_t * flags;
|
||||
int flagCount;
|
||||
FOModFile_t * files;
|
||||
int fileCount;
|
||||
TypeDescriptor_t type;
|
||||
char * name;
|
||||
} FOModPlugin_t;
|
||||
|
||||
//combine group and "plugins"
|
||||
typedef struct FOModGroup {
|
||||
FOModPlugin_t * plugins;
|
||||
int pluginCount;
|
||||
GroupType_t type;
|
||||
char * name;
|
||||
FOModOrder_t order;
|
||||
} FOModGroup_t;
|
||||
|
||||
int parseGroup(xmlNodePtr groupNode, FOModGroup_t* group);
|
||||
void freeGroup(FOModGroup_t * group);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,327 @@
|
||||
#include "parser.h"
|
||||
#include "libxml/tree.h"
|
||||
#include "xmlUtil.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
//Maybe integrate this into the rest of the code instead of freeing after the fact
|
||||
void freeFOMod(FOMod_t * fomod) {
|
||||
for(int i = 0; i < fomod->condFilesCount; i++) {
|
||||
FOModCondFile_t * condFile = &(fomod->condFiles[i]);
|
||||
for(int fileId = 0; fileId < condFile->fileCount; fileId++) {
|
||||
free(condFile->files[fileId].destination);
|
||||
free(condFile->files[fileId].source);
|
||||
}
|
||||
|
||||
for(int flagId = 0; flagId < condFile->flagCount; flagId++) {
|
||||
FOModFlag_t * flag = &(condFile->requiredFlags[flagId]);
|
||||
free(flag->name);
|
||||
free(flag->value);
|
||||
}
|
||||
free(condFile->files);
|
||||
free(condFile->requiredFlags);
|
||||
}
|
||||
free(fomod->condFiles);
|
||||
|
||||
free(fomod->moduleImage);
|
||||
free(fomod->moduleName);
|
||||
|
||||
int size = countUntilNull(fomod->requiredInstallFiles);
|
||||
for(int i = 0; i < size; i++) {
|
||||
free(fomod->requiredInstallFiles[i]);
|
||||
}
|
||||
free(fomod->requiredInstallFiles);
|
||||
|
||||
for(int i = 0; i < fomod->stepCount; i++) {
|
||||
FOModStep_t * step = &fomod->steps[i];
|
||||
for(int groupId = 0; groupId < step->groupCount; groupId++) {
|
||||
FOModGroup_t * group = &step->groups[groupId];
|
||||
freeGroup(group);
|
||||
free(step->groups[groupId].plugins);
|
||||
}
|
||||
for(int flagId = 0; flagId < step->flagCount; flagId++) {
|
||||
FOModFlag_t * flag = &(step->requiredFlags[flagId]);
|
||||
free(flag->name);
|
||||
free(flag->value);
|
||||
}
|
||||
free(step->requiredFlags);
|
||||
free(step->name);
|
||||
}
|
||||
}
|
||||
|
||||
int parseVisibleNode(xmlNodePtr node, FOModStep_t * step) {
|
||||
xmlNodePtr requiredFlagsNode = node->children;
|
||||
|
||||
while (requiredFlagsNode != NULL) {
|
||||
|
||||
if(!validateNode(&requiredFlagsNode, true, "flagDependency", NULL)) {
|
||||
//TODO: handle error
|
||||
printf("%d\n", __LINE__);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if(requiredFlagsNode == NULL)break;
|
||||
|
||||
step->flagCount += 1;
|
||||
step->requiredFlags = realloc(step->requiredFlags, step->flagCount * sizeof(FOModFlag_t));
|
||||
FOModFlag_t * flag = &(step->requiredFlags[step->flagCount - 1]);
|
||||
flag->name = freeAndDup(xmlGetProp(requiredFlagsNode, (const xmlChar *) "flag"));
|
||||
flag->value = freeAndDup(xmlGetProp(requiredFlagsNode, (const xmlChar *) "value"));
|
||||
|
||||
requiredFlagsNode = requiredFlagsNode->next;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int parseOptionalFileGroup(xmlNodePtr node, FOModStep_t * step) {
|
||||
xmlChar * optionOrder = xmlGetProp(node, (const xmlChar *)"order");
|
||||
step->optionOrder = getFOModOrder((char *)optionOrder);
|
||||
xmlFree(optionOrder);
|
||||
xmlNodePtr group = node->children;
|
||||
while(group != NULL) {
|
||||
if(!validateNode(&group, true, "group", NULL)) {
|
||||
//TODO: handle error
|
||||
printf("%d\n", __LINE__);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if(group == NULL)break;
|
||||
|
||||
step->groupCount += 1;
|
||||
step->groups = realloc(step->groups, step->groupCount * sizeof(FOModGroup_t));
|
||||
int status = parseGroup(group, &step->groups[step->groupCount - 1]);
|
||||
|
||||
if(status != EXIT_SUCCESS) {
|
||||
//TODO: handle error
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
group = group->next;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
FOModStep_t * parseInstallSteps(xmlNodePtr installStepsNode, int * stepCount) {
|
||||
FOModStep_t * steps = NULL;
|
||||
*stepCount = 0;
|
||||
|
||||
xmlNodePtr stepNode = installStepsNode->children;
|
||||
while(stepNode != NULL) {
|
||||
//skipping the text node
|
||||
if(!validateNode(&stepNode, true, "installStep", NULL)) {
|
||||
//TODO: handle error
|
||||
printf("%d\n", __LINE__);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if(stepNode == NULL)break;
|
||||
|
||||
*stepCount += 1;
|
||||
steps = realloc(steps, *stepCount * sizeof(FOModStep_t));
|
||||
|
||||
FOModStep_t * step = &steps[*stepCount - 1];
|
||||
step->name = freeAndDup(xmlGetProp(stepNode, (const xmlChar *)"name"));
|
||||
step->requiredFlags = NULL;
|
||||
step->flagCount = 0;
|
||||
step->groupCount = 0;
|
||||
step->groups = NULL;
|
||||
|
||||
xmlNodePtr stepchildren = stepNode->children;
|
||||
|
||||
while(stepchildren != NULL) {
|
||||
if(xmlStrcmp(stepchildren->name, (const xmlChar *) "visible") == 0) {
|
||||
parseVisibleNode(stepchildren, step);
|
||||
} else if(xmlStrcmp(stepchildren->name, (const xmlChar *) "optionalFileGroups") == 0) {
|
||||
parseOptionalFileGroup(stepchildren, step);
|
||||
}
|
||||
stepchildren = stepchildren->next;
|
||||
}
|
||||
|
||||
stepNode = stepNode->next;
|
||||
}
|
||||
return steps;
|
||||
}
|
||||
|
||||
int parseDependencies(xmlNodePtr node, FOModCondFile_t * condFile) {
|
||||
xmlNodePtr flagNode = node->children;
|
||||
|
||||
if(!validateNode(&flagNode, true, "flagDependency", NULL)) {
|
||||
//TODO: handle error
|
||||
printf("%d\n", __LINE__);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
while(flagNode != NULL) {
|
||||
condFile->flagCount += 1;
|
||||
condFile->requiredFlags = realloc(condFile->requiredFlags, condFile->flagCount * sizeof(FOModFlag_t));
|
||||
FOModFlag_t * flag = &(condFile->requiredFlags[condFile->flagCount - 1]);
|
||||
flag->name = freeAndDup(xmlGetProp(flagNode, (const xmlChar *) "flag"));
|
||||
flag->value = freeAndDup(xmlGetProp(flagNode, (const xmlChar *) "value"));
|
||||
|
||||
flagNode = flagNode->next;
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int parseFiles(xmlNodePtr node, FOModCondFile_t * condFile) {
|
||||
xmlNodePtr filesNode = node->children;
|
||||
|
||||
|
||||
while(filesNode != NULL) {
|
||||
if(!validateNode(&filesNode, true, "folder", "file", NULL)) {
|
||||
//TODO: handle error
|
||||
printf("%d\n", __LINE__);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
condFile->fileCount += 1;
|
||||
condFile->files = realloc(condFile->files, condFile->fileCount * sizeof(FOModFile_t));
|
||||
FOModFile_t * flag = &(condFile->files[condFile->fileCount - 1]);
|
||||
flag->source = freeAndDup(xmlGetProp(filesNode, (const xmlChar *) "source"));
|
||||
flag->destination = freeAndDup(xmlGetProp(filesNode, (const xmlChar *) "destination"));
|
||||
flag->priority = 0;
|
||||
flag->isFolder = xmlStrcmp(filesNode->name, (xmlChar *) "folder") == 0;
|
||||
|
||||
filesNode = filesNode->next;
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int parseConditionalInstalls(xmlNodePtr node, FOMod_t * fomod) {
|
||||
xmlNodePtr patterns = node->children;
|
||||
if(patterns != NULL) {
|
||||
if(!validateNode(&patterns, true, "patterns", NULL)) {
|
||||
//TODO: handle error
|
||||
printf("%d\n", __LINE__);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
xmlNodePtr currentPattern = patterns->children;
|
||||
while(currentPattern != NULL) {
|
||||
xmlNodePtr patternChild = currentPattern->children;
|
||||
|
||||
if(!validateNode(&patternChild, true, "pattern", NULL)) {
|
||||
//TODO: handle error
|
||||
printf("%d\n", __LINE__);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
while(patternChild != NULL) {
|
||||
fomod->condFilesCount += 1;
|
||||
fomod->condFiles = realloc(fomod->condFiles, fomod->condFilesCount * sizeof(FOModCondFile_t));
|
||||
FOModCondFile_t * condFile = &(fomod->condFiles[fomod->condFilesCount - 1]);
|
||||
|
||||
condFile->fileCount = 0;
|
||||
condFile->files = NULL;
|
||||
condFile->flagCount = 0;
|
||||
condFile->requiredFlags = NULL;
|
||||
|
||||
if(xmlStrcmp(patternChild->name, (xmlChar *)"dependencies") == 0) {
|
||||
if(parseDependencies(patternChild, condFile) != EXIT_SUCCESS) {
|
||||
//TODO: handle error
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
} else if(xmlStrcmp(patternChild->name, (xmlChar *)"files") == 0) {
|
||||
if(parseFiles(patternChild, condFile) != EXIT_SUCCESS) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
}
|
||||
patternChild = patternChild->next;
|
||||
}
|
||||
currentPattern = currentPattern->next;
|
||||
}
|
||||
}
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
||||
int parseFOMod(const char * fomodFile, FOMod_t* fomod) {
|
||||
xmlDocPtr doc;
|
||||
xmlNodePtr cur;
|
||||
|
||||
fomod->condFiles = NULL;
|
||||
fomod->condFilesCount = 0;
|
||||
fomod->requiredInstallFiles = NULL;
|
||||
fomod->stepCount = 0;
|
||||
fomod->stepOrder = 0;
|
||||
fomod->steps = NULL;
|
||||
fomod->moduleImage = NULL;
|
||||
fomod->moduleName = NULL;
|
||||
|
||||
doc = xmlParseFile(fomodFile);
|
||||
|
||||
if(doc == NULL) {
|
||||
fprintf(stderr, "Document is not a valid xml file\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
|
||||
cur = xmlDocGetRootElement(doc);
|
||||
if(cur == NULL) {
|
||||
fprintf(stderr, "emptyDocument");
|
||||
xmlFreeDoc(doc);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
if(xmlStrcmp(cur->name, (const xmlChar *) "config") != 0) {
|
||||
fprintf(stderr, "document of the wrong type, root node is '%s' instead of config\n", cur->name);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
cur = cur->children;
|
||||
while(cur != NULL) {
|
||||
if(xmlStrcmp(cur->name, (const xmlChar *) "moduleName") == 0) {
|
||||
//might cause some issues. when will c finally support utf-8
|
||||
fomod->moduleName = (char *)cur->content;
|
||||
} else if(xmlStrcmp(cur->name, (const xmlChar *) "moduleImage") == 0) {
|
||||
fomod->moduleImage = freeAndDup(xmlGetProp(cur, (const xmlChar *)"path"));
|
||||
} else if(xmlStrcmp(cur->name, (const xmlChar *)"requiredInstallFiles") == 0) {
|
||||
//TODO: support non empty destination.
|
||||
xmlNodePtr requiredInstallFile = cur->children;
|
||||
while(requiredInstallFile != NULL) {
|
||||
if(validateNode(&requiredInstallFile, true, "folder", "file", NULL)) {
|
||||
//TODO: handle error
|
||||
printf("%d\n", __LINE__);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int size = countUntilNull(fomod->requiredInstallFiles) + 2;
|
||||
fomod->requiredInstallFiles = realloc(fomod->requiredInstallFiles, sizeof(char *) * size);
|
||||
//ensure it is null terminated
|
||||
fomod->requiredInstallFiles[size - 1] = NULL;
|
||||
fomod->requiredInstallFiles[size - 2] = freeAndDup(xmlGetProp(requiredInstallFile, (const xmlChar *)"source"));
|
||||
|
||||
requiredInstallFile = cur->children;
|
||||
}
|
||||
} else if(xmlStrcmp(cur->name, (const xmlChar *)"installSteps") == 0) {
|
||||
if(fomod->steps != NULL) {
|
||||
fprintf(stderr, "Multiple 'installSteps' tags");
|
||||
//TODO: handle error
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
xmlChar * stepOrder = xmlGetProp(cur, (xmlChar *)"order");
|
||||
fomod->stepOrder = getFOModOrder((char *)stepOrder);
|
||||
xmlFree(stepOrder);
|
||||
|
||||
int stepCount = 0;
|
||||
FOModStep_t * steps = parseInstallSteps(cur, &stepCount);
|
||||
|
||||
if(steps == NULL) {
|
||||
fprintf(stderr, "Failed to parse the install steps\n");
|
||||
|
||||
//TODO: manage the error properly
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
fomod->steps = steps;
|
||||
fomod->stepCount = stepCount;
|
||||
} else if(xmlStrcmp(cur->name, (const xmlChar *) "conditionalFileInstalls") == 0) {
|
||||
parseConditionalInstalls(cur, fomod);
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
|
||||
xmlFreeDoc(doc);
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
#ifndef __FOMOD_PARSER_H__
|
||||
#define __FOMOD_PARSER_H__
|
||||
|
||||
|
||||
#include "group.h"
|
||||
|
||||
//combine installStep and optionalFileGroups
|
||||
typedef struct FOModStep {
|
||||
FOModOrder_t optionOrder;
|
||||
FOModGroup_t * groups;
|
||||
int groupCount;
|
||||
char * name;
|
||||
FOModFlag_t * requiredFlags;
|
||||
int flagCount;
|
||||
} FOModStep_t;
|
||||
|
||||
typedef struct FOMod {
|
||||
char * moduleName;
|
||||
char * moduleImage;
|
||||
char ** requiredInstallFiles;
|
||||
FOModOrder_t stepOrder;
|
||||
FOModStep_t * steps;
|
||||
int stepCount;
|
||||
FOModCondFile_t * condFiles;
|
||||
int condFilesCount;
|
||||
} FOMod_t;
|
||||
|
||||
int parseFOMod(const char * fomodFile, FOMod_t* fomod);
|
||||
void freeFOMod(FOMod_t * fomod);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,70 @@
|
||||
#include "xmlUtil.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
char * freeAndDup(xmlChar * line) {
|
||||
char * free = strdup((const char *) line);
|
||||
xmlFree(line);
|
||||
return free;
|
||||
}
|
||||
|
||||
FOModOrder_t getFOModOrder(const char * order) {
|
||||
if(order == NULL || strcmp(order, "Ascending") == 0) {
|
||||
return ASC;
|
||||
} else if(strcmp(order, "Explicit") == 0) {
|
||||
return ORD;
|
||||
} else if(strcmp(order, "Descending") == 0) {
|
||||
return DESC;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//replace \ in the path by /
|
||||
void fixPath(char * path) {
|
||||
while(*path != '\0') {
|
||||
if(*path == '\\')*path = '/';
|
||||
path++;
|
||||
}
|
||||
}
|
||||
|
||||
int countUntilNull(void * pointers) {
|
||||
int i = 0;
|
||||
while(pointers != NULL) {
|
||||
pointers++;
|
||||
i++;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
//names cannot contain false
|
||||
//need to be null terminated
|
||||
bool validateNode(xmlNodePtr * node, bool skipText, const char * names, ...) {
|
||||
va_list namesPtr;
|
||||
|
||||
while(*node != NULL && xmlStrcmp((*node)->name, (const xmlChar *)"text") == 0) {
|
||||
if(skipText) {
|
||||
(*node) = (*node)->next;
|
||||
} else {
|
||||
//could not skip and the node was a text node.
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if(*node == NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
va_start(namesPtr, names);
|
||||
|
||||
const char * validName = names;
|
||||
while(validName != NULL) {
|
||||
if(xmlStrcmp((*node)->name, (const xmlChar *)validName) == 0) {
|
||||
va_end(namesPtr);
|
||||
return true;
|
||||
}
|
||||
validName = va_arg(namesPtr, char *);
|
||||
}
|
||||
|
||||
va_end(namesPtr);
|
||||
return false;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#ifndef __XML_UTIL_H__
|
||||
#define __XML_UTIL_H__
|
||||
|
||||
#include <libxml/parser.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
|
||||
typedef enum FOModOrder { ASC, DESC, ORD } FOModOrder_t;
|
||||
|
||||
bool validateNode(xmlNodePtr * node, bool skipText, const char * names, ...);
|
||||
char * freeAndDup(xmlChar * line);
|
||||
FOModOrder_t getFOModOrder(const char * order);
|
||||
void fixPath(char * path);
|
||||
int countUntilNull(void * pointers);
|
||||
|
||||
#endif
|
||||
+3
-3
@@ -44,9 +44,9 @@ int un7z(const char * path, const char * outdir) {
|
||||
}
|
||||
|
||||
const char * extractLastPart(const char * filePath, const char delimeter) {
|
||||
int length = strlen(filePath);
|
||||
int index = -1;
|
||||
for(int i= length -1; i >= 0; i--) {
|
||||
const unsigned long length = strlen(filePath);
|
||||
long index = -1;
|
||||
for(long i= length - 1; i >= 0; i--) {
|
||||
if(filePath[i] == delimeter) {
|
||||
index = i + 1;
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user