diff --git a/CMakeLists.txt b/CMakeLists.txt index c40af69..0aa00af 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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) \ No newline at end of file +install(TARGETS ModManager DESTINATION bin) diff --git a/src/file.c b/src/file.c index 8d9b640..2fe36a0 100644 --- a/src/file.c +++ b/src/file.c @@ -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. diff --git a/src/fomod.c b/src/fomod.c index f2c1d05..4fd07f0 100644 --- a/src/fomod.c +++ b/src/fomod.c @@ -12,510 +12,7 @@ #include #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; diff --git a/src/fomod.h b/src/fomod.h index c0fa587..8f12725 100644 --- a/src/fomod.h +++ b/src/fomod.h @@ -2,70 +2,8 @@ #define __FOMOD_H__ #include - -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); diff --git a/src/fomod/fomodTypes.h b/src/fomod/fomodTypes.h new file mode 100644 index 0000000..616f4a8 --- /dev/null +++ b/src/fomod/fomodTypes.h @@ -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 diff --git a/src/fomod/group.c b/src/fomod/group.c new file mode 100644 index 0000000..470153a --- /dev/null +++ b/src/fomod/group.c @@ -0,0 +1,208 @@ +#include "group.h" +#include "xmlUtil.h" +#include "string.h" +#include + +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; +} diff --git a/src/fomod/group.h b/src/fomod/group.h new file mode 100644 index 0000000..27c0538 --- /dev/null +++ b/src/fomod/group.h @@ -0,0 +1,34 @@ +#ifndef __GROUP_H__ +#define __GROUP_H__ + +#include +#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 diff --git a/src/fomod/parser.c b/src/fomod/parser.c new file mode 100644 index 0000000..747ea76 --- /dev/null +++ b/src/fomod/parser.c @@ -0,0 +1,327 @@ +#include "parser.h" +#include "libxml/tree.h" +#include "xmlUtil.h" +#include + +//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; +} diff --git a/src/fomod/parser.h b/src/fomod/parser.h new file mode 100644 index 0000000..1f665fc --- /dev/null +++ b/src/fomod/parser.h @@ -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 diff --git a/src/fomod/xmlUtil.c b/src/fomod/xmlUtil.c new file mode 100644 index 0000000..4cc149a --- /dev/null +++ b/src/fomod/xmlUtil.c @@ -0,0 +1,70 @@ +#include "xmlUtil.h" + +#include + +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; +} diff --git a/src/fomod/xmlUtil.h b/src/fomod/xmlUtil.h new file mode 100644 index 0000000..95b637a --- /dev/null +++ b/src/fomod/xmlUtil.h @@ -0,0 +1,16 @@ +#ifndef __XML_UTIL_H__ +#define __XML_UTIL_H__ + +#include +#include + + +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 diff --git a/src/install.c b/src/install.c index 7be5f7c..c54ff6d 100644 --- a/src/install.c +++ b/src/install.c @@ -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;