4 Commits

Author SHA1 Message Date
Marc 3b22c49762 Merge branch 'master' of ssh.marcbarbier.fr:Marc/modmanager into interface 2022-10-13 10:38:55 +02:00
Sean Bogosavac b6996bf73b Added Skyrim to the game list 2022-10-04 12:57:17 +02:00
Sean Bogosavac c9f7e15e05 Merged master into interface 2022-10-04 11:56:07 +02:00
Sean Bogosavac 8e521eba6e Created hello world window and added gtk lib 2022-10-03 19:44:47 +02:00
45 changed files with 820 additions and 886 deletions
+27 -57
View File
@@ -9,8 +9,8 @@ if(CMAKE_BUILD_TYPE MATCHES DEBUG)
endif() endif()
set(CMAKE_C_FLAGS "-Wall -Wextra -pedantic -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wmaybe-uninitialized") set(CMAKE_C_FLAGS "-Wall -Wextra -pedantic -Wcast-qual -Wstrict-prototypes -Wmissing-prototypes -Wmissing-declarations -Wmaybe-uninitialized")
set(CMAKE_C_FLAGS_DEBUG "-g -Werror -O0") set(CMAKE_C_FLAGS_DEBUG "-g -fsanitize=address -Werror -O0")
set(CMAKE_C_FLAGS_RELEASE "") set(CMAKE_C_FLAGS_RELEASE "-g")
# generate the compile_commands for vscode / clang # generate the compile_commands for vscode / clang
set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "") set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "")
@@ -19,73 +19,43 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON CACHE INTERNAL "")
project(mod-manager) project(mod-manager)
set(LIB_SOURCES set(SOURCES
src/lib/steam.c src/steam.c
src/lib/loadOrder.c src/loadOrder.c
src/lib/install.c src/install.c
src/lib/overlayfs.c src/overlayfs.c
src/lib/gameData.c src/getDataPath.c
src/lib/getHome.c src/getHome.c
src/lib/file.c src/file.c
src/lib/order.c src/order.c
src/lib/archives.c src/archives.c
src/lib/fomod.c src/fomod.c
src/lib/deploy.c src/fomod/group.c
src/lib/fomod/group.c src/fomod/xmlUtil.c
src/lib/fomod/xmlUtil.c src/fomod/parser.c
src/lib/fomod/parser.c src/gui/guiMain.c
)
# Headers files to export in the include folder
set(LIB_PUBLIC_HEADERS
src/include/constants.h
src/include/deploy.h
src/include/errorType.h
src/include/file.h
src/include/fomod.h
src/include/gameData.h
src/include/getHome.h
src/include/install.h
src/include/loadOrder.h
src/include/order.h
src/include/steam.h
)
set(CLI_SOURCES
src/cli/cli.c
src/cli/fomod.c
) )
# add the executable # add the executable
add_executable(mod-manager ${CLI_SOURCES}) add_executable(mod-manager src/main.c ${SOURCES})
add_library(libmod-manager SHARED ${LIB_SOURCES})
set_target_properties(libmod-manager PROPERTIES PUBLIC_HEADER ${LIB_PUBLIC_HEADERS})
find_package(PkgConfig REQUIRED) find_package(PkgConfig REQUIRED)
pkg_search_module(GLIB REQUIRED glib-2.0) pkg_search_module(GLIB REQUIRED glib-2.0)
pkg_search_module(AUDIT REQUIRED audit) pkg_search_module(AUDIT REQUIRED audit)
pkg_search_module(LIBXML REQUIRED libxml-2.0) pkg_search_module(LIBXML REQUIRED libxml-2.0)
pkg_search_module(GTK REQUIRED gtk4)
target_include_directories(libmod-manager PUBLIC src/include ${GLIB_INCLUDE_DIRS} ${LIBXML_INCLUDE_DIRS} ${AUDIT_INCLUDE_DIRS})
target_link_libraries(libmod-manager ${GLIB_LDFLAGS})
target_link_libraries(libmod-manager ${LIBXML_LIBRARIES})
target_link_libraries(libmod-manager ${AUDIT_LIBRARIES})
target_link_libraries(mod-manager libmod-manager)
target_include_directories(mod-manager PUBLIC src/include)
target_link_libraries(mod-manager ${GLIB_LDFLAGS})
target_include_directories(mod-manager PRIVATE ${GLIB_INCLUDE_DIRS}) target_include_directories(mod-manager PRIVATE ${GLIB_INCLUDE_DIRS})
target_include_directories(mod-manager PRIVATE ${LIBXML_INCLUDE_DIRS})
target_include_directories(mod-manager PRIVATE ${AUDIT_INCLUDE_DIRS})
target_include_directories(mod-manager PRIVATE ${GTK_INCLUDE_DIRS})
install(TARGETS mod-manager OPTIONAL DESTINATION bin) target_link_libraries(mod-manager ${GLIB_LDFLAGS})
target_link_libraries(mod-manager ${LIBXML_LIBRARIES})
target_link_libraries(mod-manager ${AUDIT_LIBRARIES})
target_link_libraries(mod-manager ${GTK_LIBRARIES})
install(TARGETS libmod-manager install(TARGETS mod-manager DESTINATION bin)
LIBRARY DESTINATION lib
PUBLIC_HEADER DESTINATION include/mod-manager
)
set_property(TARGET mod-manager PROPERTY C_STANDARD 23) set_property(TARGET mod-manager PROPERTY C_STANDARD 23)
set_property(TARGET libmod-manager PROPERTY C_STANDARD 23)
#avoid having liblibmod-manager
set_target_properties(libmod-manager PROPERTIES PREFIX "")
-4
View File
@@ -1,4 +0,0 @@
* Add tests
* Add safe interrupt support
* Add a gui in an external binary
* make the CLI into a separate binary
+1 -1
View File
@@ -6,7 +6,7 @@ pkgdesc="a Mod manager for bethesda games"
arch=('x86_64') # might work on other archs but i can not try arch=('x86_64') # might work on other archs but i can not try
url='https://gitlab.marcbarbier.fr/Marc/modmanager' url='https://gitlab.marcbarbier.fr/Marc/modmanager'
license=('GPL2') license=('GPL2')
source=( 'git+https://github.com/Marc-Pierre-Barbier/ModManager.git' ) source=( 'git+https://gitlab.marcbarbier.fr/Marc/modmanager.git' )
md5sums=( 'SKIP' ) md5sums=( 'SKIP' )
optdepends=('fuse-overlayfs: special filesystem support' ) optdepends=('fuse-overlayfs: special filesystem support' )
+2 -3
View File
@@ -2,18 +2,17 @@
## Function names ## Function names
### header functions ### shared functions
function should start by the name of their module in camelCase followed by an underscore and the name of the function in camelCase function should start by the name of their module in camelCase followed by an underscore and the name of the function in camelCase
example: example:
steam_searchGames() steam_searchGames()
if the function has the same name as the module then it doesn't need to be repeated.
### static functions ### static functions
all static functions should be in camelCase and they should not mention their module. there is no rule for now
## Struct names ## Struct names
-2
View File
@@ -1,2 +0,0 @@
#define APP_NAME "mod-manager CLI"
#define VERSION "0.1"
-204
View File
@@ -1,204 +0,0 @@
#include "fomod.h"
#include <fomod.h>
#include <constants.h>
#include <stdbool.h>
#include <stdio.h>
#include <unistd.h>
//match the definirion of gcompare func
static gint fomod_flagEqual(const fomod_Flag_t * a, const fomod_Flag_t * b) {
int nameCmp = strcmp(a->name, b->name);
if(nameCmp == 0) {
if(strcmp(a->value, b->value) == 0)
//is equal
return 0;
return 1;
}
return nameCmp;
}
static int getInputCount(const char * input) {
char buff[2];
buff[1] = '\0';
int elementCount = 0;
bool prevWasValue = false;
for(int i = 0; input[i] != '\0' && input[i] != '\n'; i++) {
buff[0] = input[i];
//if the character is a valid character
if(strstr("0123456789 ", buff) != NULL) {
if(input[i] == ' ') prevWasValue = false;
else if(!prevWasValue) {
prevWasValue = true;
elementCount++;
}
} else {
return -1;
}
}
return elementCount;
}
static void fomod_printOptionsInOrder(fomod_Group_t group) {
for(int i = 0; i < group.pluginCount; i++) {
printf("%d, %s\n", i, group.plugins[i].name);
printf("%s\n", group.plugins[i].description);
}
}
error_t fomod_installFOMod(const char * modFolder, const char * destination) {
//everything should be lowercase since we use casefold() before calling any install function
char * fomodFolder = g_build_path("/", modFolder, "fomod", NULL);
char * fomodFile = g_build_filename(fomodFolder, "moduleconfig.xml", NULL);
printf("%s", fomodFile);
if(access(fomodFile, F_OK) != 0) {
fprintf(stderr, "FOMod file not found, are you sure this is a fomod mod ?\n");
g_free(fomodFolder);
g_free(fomodFile);
return ERR_FAILURE;
}
FOMod_t fomod;
int returnValue = parser_parseFOMod(fomodFile, &fomod);
if(returnValue == ERR_FAILURE)
return ERR_FAILURE;
g_free(fomodFile);
GList * flagList = NULL;
GList * pendingFileOperations = NULL;
for(int i = 0; i < fomod.stepCount; i++) {
const FOModStep_t * step = &fomod.steps[i];
bool validFlags = true;
for(int flagId = 0; flagId < step->flagCount; flagId++) {
const GList * flagLink = g_list_find_custom(flagList, &step->requiredFlags[flagId], (GCompareFunc)fomod_flagEqual);
if(flagLink == NULL) {
validFlags = false;
break;
}
}
if(!validFlags) continue;
for(int groupId = 0; groupId < step->groupCount; groupId++ ) {
fomod_Group_t group = step->groups[groupId];
u_int8_t min;
u_int8_t max;
int inputCount = 0;
char *inputBuffer = NULL;
size_t bufferSize = 0;
while(true) {
fomod_printOptionsInOrder(group);
switch(group.type) {
case ONE_ONLY:
printf("Select one :\n");
min = 1;
max = 1;
break;
case ANY:
printf("Select any (space separated) (leave empty for nothing) :\n");
min = 0;
max = (u_int8_t)group.pluginCount;
break;
case AT_LEAST_ONE:
printf("Select at least one (space separated) (leave empty for nothing) :\n");
min = 1;
max = (u_int8_t)group.pluginCount;
break;
case AT_MOST_ONE:
printf("Select one or none (space separated) (leave empty for nothing) :\n");
min = 0;
max = 1;
break;
case ALL:
printf("Press enter to continue\n");
min = 0;
max = 0;
break;
default:
//never happen;
fprintf(stderr, "unexpected type please report this issue %d, %d", group.type, __LINE__);
return ERR_FAILURE;
}
if(getline(&inputBuffer, &bufferSize, stdin) > 0) {
inputCount = getInputCount(inputBuffer);
if(inputCount <= max && inputCount >= min) {
printf("Continuing\n");
break;
}
fprintf(stderr, "Invalid input\n");
if(inputBuffer != NULL)free(inputBuffer);
inputBuffer = NULL;
} else {
//TODO: handle error
}
}
//processing user input
GRegex* regex = g_regex_new("\\s*", 0, 0, NULL);
char ** choices = g_regex_split(regex, inputBuffer, 0);
g_regex_unref(regex);
for(int choiceId = 0; choices[choiceId] != NULL; choiceId++) {
//TODO: safer user input
int choice = atoi(choices[choiceId]);
fomod_Plugin_t plugin = group.plugins[choice];
for(int flagId = 0; flagId < plugin.flagCount; flagId++) {
flagList = g_list_append(flagList, &plugin.flags[flagId]);
}
//do the install
for(int pluginId = 0; pluginId < plugin.fileCount; pluginId++) {
const fomod_File_t * file = &plugin.files[pluginId];
fomod_File_t * fileCopy = malloc(sizeof(fomod_File_t));
*fileCopy = *file;
//changing pathes to lowercase since we used casefold and the pathes in the xml might not like it
char * destination = g_ascii_strdown(file->destination, -1);
fileCopy->destination = strdup(destination);
g_free(destination);
char * source = g_ascii_strdown(file->source, -1);
fileCopy->source = strdup(source);
g_free(source);
pendingFileOperations = g_list_append(pendingFileOperations, fileCopy);
}
}
g_strfreev(choices);
if(inputBuffer != NULL)free(inputBuffer);
}
}
//TODO: manage multiple files with the same name
pendingFileOperations = fomod_processCondFiles(&fomod, flagList, pendingFileOperations);
fomod_processFileOperations(&pendingFileOperations, modFolder, destination);
printf("FOMod successfully installed!\n");
g_list_free(flagList);
fomod_freeFileOperations(pendingFileOperations);
fomod_freeFOMod(&fomod);
g_free(fomodFolder);
return ERR_SUCCESS;
}
-10
View File
@@ -1,10 +0,0 @@
#include <fomod.h>
/**
* @brief Start a terminal based install process for fomod.
*
* @param modFolder folder of the fomod file.
* @param destination folder of the new mod that contains the result of the fomod process.
* @return int
*/
error_t fomod_installFOMod(const char * modFolder, const char * destination);
-18
View File
@@ -150,21 +150,3 @@ const char * file_extractExtension(const char * filePath) {
const char * file_extractFileName(const char * filePath) { const char * file_extractFileName(const char * filePath) {
return file_extractLastPart(filePath, '/'); return file_extractLastPart(filePath, '/');
} }
GList * file_listFolderContent(const char * path) {
GList * list = NULL;
DIR *d;
struct dirent *dir;
d = opendir(path);
if (d) {
while ((dir = readdir(d)) != NULL) {
//removes .. & . from the list
if(strcmp(dir->d_name, "..") != 0 && strcmp(dir->d_name, ".") != 0) {
list = g_list_append(list, strdup(dir->d_name));
}
}
closedir(d);
}
return list;
}
+1 -5
View File
@@ -2,10 +2,8 @@
#define __FILE_H__ #define __FILE_H__
#include <stdbool.h> #include <stdbool.h>
#include <glib.h>
#include <sys/types.h> #include <sys/types.h>
#include "main.h"
#include "constants.h"
//valid copy flags //valid copy flags
@@ -64,6 +62,4 @@ const char * file_extractExtension(const char * filePath);
*/ */
const char * file_extractFileName(const char * filePath); const char * file_extractFileName(const char * filePath);
GList * file_listFolderContent(const char * path);
#endif #endif
+405
View File
@@ -0,0 +1,405 @@
#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/xmlstring.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdarg.h>
#include <unistd.h>
#include "fomod.h"
#include "file.h"
#include "fomod/fomodTypes.h"
#include "fomod/group.h"
#include "libxml/globals.h"
#include "main.h"
static int getInputCount(const char * input) {
char buff[2];
buff[1] = '\0';
int elementCount = 0;
bool prevWasValue = false;
for(int i = 0; input[i] != '\0' && input[i] != '\n'; i++) {
buff[0] = input[i];
//if the character is a valid character
if(strstr("0123456789 ", buff) != NULL) {
if(input[i] == ' ') prevWasValue = false;
else if(!prevWasValue) {
prevWasValue = true;
elementCount++;
}
} else {
return -1;
}
}
return elementCount;
}
static gint priorityCmp(gconstpointer a, gconstpointer b) {
const fomod_File_t * fileA = (const fomod_File_t *)a;
const fomod_File_t * fileB = (const fomod_File_t *)b;
return fileB->priority - fileA->priority;
}
static void fomod_printOptionsInOrder(fomod_Group_t group) {
for(int i = 0; i < group.pluginCount; i++) {
printf("%d, %s\n", i, group.plugins[i].name);
printf("%s\n", group.plugins[i].description);
}
}
static gint fomod_flagEqual(const fomod_Flag_t * a, const fomod_Flag_t * b) {
int nameCmp = strcmp(a->name, b->name);
if(nameCmp == 0) {
if(strcmp(a->value, b->value) == 0)
//is equal
return 0;
return 1;
}
return nameCmp;
}
static int stepCmpAsc(const void * stepA, const void * stepB) {
const FOModStep_t * step1 = (const FOModStep_t *)stepA;
const FOModStep_t * step2 = (const FOModStep_t *)stepB;
return strcmp(step1->name, step2->name);
}
static int stepCmpDesc(const void * stepA, const void * stepB) {
const FOModStep_t * step1 = (const FOModStep_t *)stepA;
const FOModStep_t * step2 = (const FOModStep_t *)stepB;
return 1 - strcmp(step1->name, step2->name);
}
static void fomod_sortSteps(FOMod_t * fomod) {
switch(fomod->stepOrder) {
case ASC:
qsort(fomod->steps, fomod->stepCount, sizeof(*fomod->steps), stepCmpAsc);
break;
case DESC:
qsort(fomod->steps, fomod->stepCount, sizeof(*fomod->steps), stepCmpDesc);
break;
case ORD:
//ord mean that we keep the curent order, so no need to sort anything.
break;
}
}
static int fomod_groupCmpAsc(const void * stepA, const void * stepB) {
const fomod_Group_t * step1 = (const fomod_Group_t *)stepA;
const fomod_Group_t * step2 = (const fomod_Group_t *)stepB;
return strcmp(step1->name, step2->name);
}
static int fomod_groupCmpDesc(const void * stepA, const void * stepB) {
const fomod_Group_t * step1 = (const fomod_Group_t *)stepA;
const fomod_Group_t * step2 = (const fomod_Group_t *)stepB;
return 1 - strcmp(step1->name, step2->name);
}
static void fomod_sortGroup(fomod_Group_t * group) {
switch(group->order) {
case ASC:
qsort(group->plugins, group->pluginCount, sizeof(*group->plugins), fomod_groupCmpAsc);
break;
case DESC:
qsort(group->plugins, group->pluginCount, sizeof(*group->plugins), fomod_groupCmpDesc);
break;
case ORD:
//ord mean that we keep the curent order, so no need to sort anything.
break;
}
}
//TODO: handle error
error_t fomod_processFileOperations(GList ** pendingFileOperations, const char * modFolder, const char * destination) {
//priority higher a less important and should be processed first.
*pendingFileOperations = g_list_sort(*pendingFileOperations, priorityCmp);
GList * currentFileOperation = *pendingFileOperations;
while(currentFileOperation != NULL) {
//TODO: support destination
//no using link since priority is made to override files and link is annoying to deal with when overriding files.
const fomod_File_t * file = (const fomod_File_t *)currentFileOperation->data;
char * source = g_build_path("/", modFolder, file->source, NULL);
//fix the / and \ windows - unix paths
xml_fixPath(source);
int copyResult;
if(file->isFolder) {
copyResult = file_copy(source, destination, FILE_CP_NO_TARGET_DIR | FILE_CP_RECURSIVE);
} else {
copyResult = file_copy(source, destination, 0);
}
if(copyResult != EXIT_SUCCESS) {
fprintf(stderr, "Copy failed, some file might be corrupted\n");
}
g_free(source);
currentFileOperation = g_list_next(currentFileOperation);
}
return ERR_SUCCESS;
}
GList * fomod_processCondFiles(const FOMod_t * fomod, GList * flagList, GList * pendingFileOperations) {
for(int condId = 0; condId < fomod->condFilesCount; condId++) {
const fomod_CondFile_t *condFile = &fomod->condFiles[condId];
bool areAllFlagsValid = true;
//checking if all flags are valid
for(long flagId = 0; flagId < condFile->flagCount; flagId++) {
const GList * link = g_list_find_custom(flagList, &(condFile->requiredFlags[flagId]), (GCompareFunc)fomod_flagEqual);
if(link == NULL) {
areAllFlagsValid = false;
break;
}
}
if(areAllFlagsValid) {
for(long fileId = 0; fileId < condFile->flagCount; fileId++) {
const fomod_File_t * file = &(condFile->files[fileId]);
fomod_File_t * fileCopy = malloc(sizeof(*file));
*fileCopy = *file;
//changing pathes to lowercase since we used casefold and the pathes in the xml might not like it
char * destination = g_ascii_strdown(file->destination, -1);
fileCopy->destination = destination;
char * source = g_ascii_strdown(file->source, -1);
fileCopy->source = source;
pendingFileOperations = g_list_append(pendingFileOperations, fileCopy);
}
}
}
return pendingFileOperations;
}
void fomod_freeFileOperations(GList * fileOperations) {
GList * fileOperationsStart = fileOperations;
while(fileOperations != NULL) {
fomod_File_t * file = (fomod_File_t *)fileOperations->data;
if(file->destination != NULL)free(file->destination);
if(file->source != NULL)free(file->source);
fileOperations = g_list_next(fileOperations);
}
g_list_free_full(fileOperationsStart, free);
}
error_t fomod_installFOMod(const char * modFolder, const char * destination) {
//everything should be lowercase since we use casefold() before calling any install function
char * fomodFolder = g_build_path("/", modFolder, "fomod", NULL);
char * fomodFile = g_build_filename(fomodFolder, "moduleconfig.xml", NULL);
if(access(fomodFile, F_OK) != 0) {
fprintf(stderr, "FOMod file not found, are you sure this is a fomod mod ?\n");
g_free(fomodFolder);
g_free(fomodFile);
return ERR_FAILURE;
}
FOMod_t fomod;
int returnValue = parser_parseFOMod(fomodFile, &fomod);
if(returnValue == ERR_FAILURE)
return ERR_FAILURE;
g_free(fomodFile);
GList * flagList = NULL;
GList * pendingFileOperations = NULL;
fomod_sortSteps(&fomod);
for(int i = 0; i < fomod.stepCount; i++) {
const FOModStep_t * step = &fomod.steps[i];
bool validFlags = true;
for(int flagId = 0; flagId < step->flagCount; flagId++) {
const GList * flagLink = g_list_find_custom(flagList, &step->requiredFlags[flagId], (GCompareFunc)fomod_flagEqual);
if(flagLink == NULL) {
validFlags = false;
break;
}
}
if(!validFlags) continue;
for(int groupId = 0; groupId < step->groupCount; groupId++ ) {
fomod_Group_t group = step->groups[groupId];
fomod_sortGroup(&group);
u_int8_t min;
u_int8_t max;
int inputCount = 0;
char *inputBuffer = NULL;
size_t bufferSize = 0;
while(true) {
fomod_printOptionsInOrder(group);
switch(group.type) {
case ONE_ONLY:
printf("Select one :\n");
min = 1;
max = 1;
break;
case ANY:
printf("Select any (space separated) (leave empty for nothing) :\n");
min = 0;
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 = (u_int8_t)group.pluginCount - 1;
break;
case AT_MOST_ONE:
printf("Select one or none (space separated) (leave empty for nothing) :\n");
min = 0;
max = 1;
break;
case ALL:
printf("Press enter to continue\n");
min = 0;
max = 0;
break;
default:
//never happen;
fprintf(stderr, "unexpected type please report this issue %d, %d", group.type, __LINE__);
return ERR_FAILURE;
}
if(getline(&inputBuffer, &bufferSize, stdin) > 0) {
inputCount = getInputCount(inputBuffer);
if(inputCount <= max && inputCount >= min) {
printf("Continuing\n");
break;
}
fprintf(stderr, "Invalid input\n");
if(inputBuffer != NULL)free(inputBuffer);
inputBuffer = NULL;
} else {
//TODO: handle error
}
}
//processing user input
GRegex* regex = g_regex_new("\\s*", 0, 0, NULL);
char ** choices = g_regex_split(regex, inputBuffer, 0);
g_regex_unref(regex);
for(int choiceId = 0; choices[choiceId] != NULL; choiceId++) {
//TODO: safer user input
int choice = atoi(choices[choiceId]);
fomod_Plugin_t plugin = group.plugins[choice];
for(int flagId = 0; flagId < plugin.flagCount; flagId++) {
flagList = g_list_append(flagList, &plugin.flags[flagId]);
}
//do the install
for(int pluginId = 0; pluginId < plugin.fileCount; pluginId++) {
const fomod_File_t * file = &plugin.files[pluginId];
fomod_File_t * fileCopy = malloc(sizeof(fomod_File_t));
*fileCopy = *file;
//changing pathes to lowercase since we used casefold and the pathes in the xml might not like it
char * destination = g_ascii_strdown(file->destination, -1);
fileCopy->destination = strdup(destination);
g_free(destination);
char * source = g_ascii_strdown(file->source, -1);
fileCopy->source = strdup(source);
g_free(source);
pendingFileOperations = g_list_append(pendingFileOperations, fileCopy);
}
}
g_strfreev(choices);
if(inputBuffer != NULL)free(inputBuffer);
}
}
//TODO: manage multiple files with the same name
pendingFileOperations = fomod_processCondFiles(&fomod, flagList, pendingFileOperations);
fomod_processFileOperations(&pendingFileOperations, modFolder, destination);
printf("FOMod successfully installed!\n");
g_list_free(flagList);
fomod_freeFileOperations(pendingFileOperations);
fomod_freeFOMod(&fomod);
g_free(fomodFolder);
return ERR_SUCCESS;
}
void fomod_freeFOMod(FOMod_t * fomod) {
for(int i = 0; i < fomod->condFilesCount; i++) {
fomod_CondFile_t * condFile = &(fomod->condFiles[i]);
for(long fileId = 0; fileId < condFile->fileCount; fileId++) {
free(condFile->files[fileId].destination);
free(condFile->files[fileId].source);
}
for(long flagId = 0; flagId < condFile->flagCount; flagId++) {
fomod_Flag_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 = fomod_countUntilNull(fomod->requiredInstallFiles, sizeof(char **));
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++) {
fomod_Group_t * group = &step->groups[groupId];
grp_freeGroup(group);
}
for(int flagId = 0; flagId < step->flagCount; flagId++) {
fomod_Flag_t * flag = &(step->requiredFlags[flagId]);
free(flag->name);
free(flag->value);
}
free(step->groups);
free(step->requiredFlags);
free(step->name);
}
free(fomod->steps);
//set every counter to zero and every pointer to null
memset(fomod, 0, sizeof(FOMod_t));
}
+13 -8
View File
@@ -1,17 +1,22 @@
#ifndef __PUBLIC_FOMOD_H__ #ifndef __FOMOD_H__
#define __PUBLIC_FOMOD_H__ #define __FOMOD_H__
#include "errorType.h" #include <stdbool.h>
#include <glib.h> #include <glib.h>
#include "fomodTypes.h"
#include "main.h"
#include "fomod/parser.h"
#include "fomod/group.h"
#include "fomod/xmlUtil.h"
/** /**
* @brief parse a fomod xml file (found inside the mod folder /fomod/moduleconfig.xml (everything should be lowercase)) * @brief Start a terminal based install process for fomod.
* *
* @param fomodFile path to the moduleconfig.xml * @param modFolder folder of the fomod file.
* @param fomod pointer to a new FOMod_t * @param destination folder of the new mod that contains the result of the fomod process.
* @return int
*/ */
error_t parser_parseFOMod(const char * fomodFile, FOMod_t* fomod); error_t fomod_installFOMod(const char * modFolder, const char * destination);
/** /**
* @brief In fomod there is file operations which depends on multiple flags this function find the ones that mach our current flags and append them to a list. * @brief In fomod there is file operations which depends on multiple flags this function find the ones that mach our current flags and append them to a list.
+28
View File
@@ -0,0 +1,28 @@
#ifndef __FOMOD_TYPES_H__
#define __FOMOD_TYPES_H__
#include "stdbool.h"
#include "xmlUtil.h"
typedef struct fomod_Flag {
char * name;
char * value;
} fomod_Flag_t;
typedef struct fomod_File {
char * source;
char * destination;
int priority;
bool isFolder;
} fomod_File_t;
typedef struct fomod_CondFile {
fomod_Flag_t * requiredFlags;
unsigned int flagCount;
fomod_File_t * files;
unsigned int fileCount;
} fomod_CondFile_t;
#endif
+35
View File
@@ -0,0 +1,35 @@
#ifndef __GROUP_H__
#define __GROUP_H__
#include <libxml/parser.h>
#include "fomodTypes.h"
#include "xmlUtil.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 fomod_Plugin {
char * description;
char * image;
fomod_Flag_t * flags;
int flagCount;
fomod_File_t * files;
int fileCount;
TypeDescriptor_t type;
char * name;
} fomod_Plugin_t;
//combine group and "plugins"
typedef struct fomod_Group {
fomod_Plugin_t * plugins;
int pluginCount;
GroupType_t type;
char * name;
fomod_Order_t order;
} fomod_Group_t;
int grp_parseGroup(xmlNodePtr groupNode, fomod_Group_t* group);
void grp_freeGroup(fomod_Group_t * group);
#endif
+2 -61
View File
@@ -1,4 +1,5 @@
#include <fomod.h> #include "parser.h"
#include "fomodTypes.h"
#include "group.h" #include "group.h"
#include "libxml/tree.h" #include "libxml/tree.h"
#include "xmlUtil.h" #include "xmlUtil.h"
@@ -192,58 +193,6 @@ static int parseConditionalInstalls(xmlNodePtr node, FOMod_t * fomod) {
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
static int stepCmpAsc(const void * stepA, const void * stepB) {
const FOModStep_t * step1 = (const FOModStep_t *)stepA;
const FOModStep_t * step2 = (const FOModStep_t *)stepB;
return strcmp(step1->name, step2->name);
}
static int stepCmpDesc(const void * stepA, const void * stepB) {
const FOModStep_t * step1 = (const FOModStep_t *)stepA;
const FOModStep_t * step2 = (const FOModStep_t *)stepB;
return 1 - strcmp(step1->name, step2->name);
}
static void fomod_sortSteps(FOMod_t * fomod) {
switch(fomod->stepOrder) {
case ASC:
qsort(fomod->steps, fomod->stepCount, sizeof(*fomod->steps), stepCmpAsc);
break;
case DESC:
qsort(fomod->steps, fomod->stepCount, sizeof(*fomod->steps), stepCmpDesc);
break;
case ORD:
//ord mean that we keep the curent order, so no need to sort anything.
break;
}
}
static int fomod_groupCmpAsc(const void * stepA, const void * stepB) {
const fomod_Group_t * step1 = (const fomod_Group_t *)stepA;
const fomod_Group_t * step2 = (const fomod_Group_t *)stepB;
return strcmp(step1->name, step2->name);
}
static int fomod_groupCmpDesc(const void * stepA, const void * stepB) {
const fomod_Group_t * step1 = (const fomod_Group_t *)stepA;
const fomod_Group_t * step2 = (const fomod_Group_t *)stepB;
return 1 - strcmp(step1->name, step2->name);
}
static void fomod_sortGroup(fomod_Group_t * group) {
switch(group->order) {
case ASC:
qsort(group->plugins, group->pluginCount, sizeof(*group->plugins), fomod_groupCmpAsc);
break;
case DESC:
qsort(group->plugins, group->pluginCount, sizeof(*group->plugins), fomod_groupCmpDesc);
break;
case ORD:
//ord mean that we keep the curent order, so no need to sort anything.
break;
}
}
error_t parser_parseFOMod(const char * fomodFile, FOMod_t* fomod) { error_t parser_parseFOMod(const char * fomodFile, FOMod_t* fomod) {
xmlDocPtr doc; xmlDocPtr doc;
xmlNodePtr cur; xmlNodePtr cur;
@@ -332,14 +281,6 @@ error_t parser_parseFOMod(const char * fomodFile, FOMod_t* fomod) {
cur = cur->next; cur = cur->next;
} }
//steps are in a specific order in fomod config. we need to make sure we respected this order
fomod_sortSteps(fomod);
//same for the plugins inside the groups
for(int i = 0; i < fomod->stepCount; i++)
for(int j = 0; j < fomod->steps[i].groupCount; j++)
fomod_sortGroup(&(fomod->steps[i].groups[j]));
xmlFreeDoc(doc); xmlFreeDoc(doc);
return ERR_SUCCESS; return ERR_SUCCESS;
} }
+38
View File
@@ -0,0 +1,38 @@
#ifndef __FOMOD_PARSER_H__
#define __FOMOD_PARSER_H__
#include "fomodTypes.h"
#include "group.h"
#include "../main.h"
//combine installStep and optionalFileGroups
typedef struct FOModStep {
fomod_Order_t optionOrder;
fomod_Group_t * groups;
int groupCount;
char * name;
fomod_Flag_t * requiredFlags;
int flagCount;
} FOModStep_t;
typedef struct FOMod {
char * moduleName;
char * moduleImage;
char ** requiredInstallFiles;
fomod_Order_t stepOrder;
FOModStep_t * steps;
int stepCount;
fomod_CondFile_t * condFiles;
int condFilesCount;
} FOMod_t;
/**
* @brief parse a fomod xml file (found inside the mod folder /fomod/moduleconfig.xml (everything should be lowercase))
*
* @param fomodFile path to the moduleconfig.xml
* @param fomod pointer to a new FOMod_t
*/
error_t parser_parseFOMod(const char * fomodFile, FOMod_t* fomod);
#endif
@@ -3,7 +3,9 @@
#include <libxml/parser.h> #include <libxml/parser.h>
#include <stdbool.h> #include <stdbool.h>
#include <fomod.h>
typedef enum FOModOrder { ASC, DESC, ORD } fomod_Order_t;
/** /**
* @brief * @brief
+4 -4
View File
@@ -1,14 +1,14 @@
#include <constants.h> #include "getDataPath.h"
#include <gameData.h> #include "main.h"
#include <steam.h> #include "steam.h"
#include <glib.h> #include <glib.h>
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <stdio.h> #include <stdio.h>
error_t gameData_getDataPath(int appid, char ** destination) { error_t getDataPath(int appid, char ** destination) {
GHashTable * gamePaths; GHashTable * gamePaths;
error_t status = steam_searchGames(&gamePaths); error_t status = steam_searchGames(&gamePaths);
if(status == ERR_FAILURE) { if(status == ERR_FAILURE) {
+5 -5
View File
@@ -1,8 +1,7 @@
#ifndef __GAME_DATA_H__ #ifndef __DATA_PATH_H__
#define __GAME_DATA_H__ #define __DATA_PATH_H__
#include "main.h"
#include "errorType.h"
/** /**
* @brief Get the path to the data folder * @brief Get the path to the data folder
@@ -10,6 +9,7 @@
* @param destination pointer to a null char * variable. it's value will be allocated with malloc * @param destination pointer to a null char * variable. it's value will be allocated with malloc
* @return error_t * @return error_t
*/ */
error_t gameData_getDataPath(int appid, char ** destination); error_t getDataPath(int appid, char ** destination);
#endif #endif
View File
+1 -4
View File
@@ -1,5 +1,4 @@
#ifndef __GET_HOME_H__
#define __GET_HOME_H__
/** /**
* @brief Get the user home dir regardless if he used sudo. * @brief Get the user home dir regardless if he used sudo.
@@ -7,5 +6,3 @@
* @return char* path to the home dir * @return char* path to the home dir
*/ */
char * getHome(void); char * getHome(void);
#endif
+46
View File
@@ -0,0 +1,46 @@
#include "guiMain.h"
#include "../steam.h"
#include <gtk/gtk.h>
static void print_hello(GtkWidget *widget, gpointer data) {
g_print("Hello World\n");
}
static void activate(GtkApplication *app, gpointer user_data) {
GtkWidget *window;
GtkWidget *button;
GtkWidget *box;
window = gtk_application_window_new(app);
gtk_window_set_title(GTK_WINDOW(window), "Mod Manager");
gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);
box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_widget_set_halign(box, GTK_ALIGN_CENTER);
gtk_widget_set_valign(box, GTK_ALIGN_CENTER);
gtk_window_set_child(GTK_WINDOW(window), box);
button = gtk_button_new_with_label("Hello World");
g_signal_connect(button, "clicked", G_CALLBACK(print_hello), NULL);
g_signal_connect_swapped(button, "clicked", G_CALLBACK(gtk_window_destroy), window);
gtk_box_append(GTK_BOX(box), button);
gtk_widget_show(window);
}
int guiMain(int argc, char **argv) {
GtkApplication *app;
int status;
app = gtk_application_new("fr.marcbarbier.modmanager", G_APPLICATION_DEFAULT_FLAGS);
g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
status = g_application_run(G_APPLICATION(app), 1, argv);
g_object_unref(app);
return status;
}
+6
View File
@@ -0,0 +1,6 @@
#ifndef __GUIMAIN_H__
#define __GUIMAIN_H__
int guiMain(int argc, char **argv);
#endif
-10
View File
@@ -1,10 +0,0 @@
#ifndef __DEPLOY_H__
#define __DEPLOY_H__
#include <glib.h>
typedef enum deploymentErrors { INVALID_APPID, GAME_NOT_FOUND, OK, CANNOT_MOUNT, FUSE_NOT_INSTALLED, BUG } deploymentErrors_t;
[[nodiscard]] deploymentErrors_t deploy(char * appIdStr, GList ** ignoredMods);
#endif
-6
View File
@@ -1,6 +0,0 @@
#ifndef __ERROR_TYPE_H__
#define __ERROR_TYPE_H__
typedef enum { ERR_SUCCESS, ERR_FAILURE } error_t;
#endif
-71
View File
@@ -1,71 +0,0 @@
#ifndef __FOMOD_TYPES_H__
#define __FOMOD_TYPES_H__
#include "stdbool.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 enum FOModOrder { ASC, DESC, ORD } fomod_Order_t;
typedef struct fomod_Flag {
char * name;
char * value;
} fomod_Flag_t;
typedef struct fomod_File {
char * source;
char * destination;
int priority;
bool isFolder;
} fomod_File_t;
typedef struct fomod_CondFile {
fomod_Flag_t * requiredFlags;
unsigned int flagCount;
fomod_File_t * files;
unsigned int fileCount;
} fomod_CondFile_t;
typedef struct fomod_Plugin {
char * description;
char * image;
fomod_Flag_t * flags;
int flagCount;
fomod_File_t * files;
int fileCount;
TypeDescriptor_t type;
char * name;
} fomod_Plugin_t;
//combine group and "plugins"
typedef struct fomod_Group {
fomod_Plugin_t * plugins;
int pluginCount;
GroupType_t type;
char * name;
fomod_Order_t order;
} fomod_Group_t;
//combine installStep and optionalFileGroups
typedef struct FOModStep {
fomod_Order_t optionOrder;
fomod_Group_t * groups;
int groupCount;
char * name;
fomod_Flag_t * requiredFlags;
int flagCount;
} FOModStep_t;
typedef struct FOMod {
char * moduleName;
char * moduleImage;
char ** requiredInstallFiles;
fomod_Order_t stepOrder;
FOModStep_t * steps;
int stepCount;
fomod_CondFile_t * condFiles;
int condFilesCount;
} FOMod_t;
#endif
+3 -4
View File
@@ -4,9 +4,8 @@
#include <unistd.h> #include <unistd.h>
#include <glib.h> #include <glib.h>
#include <install.h> #include "install.h"
#include "main.h"
#include <constants.h>
#include "archives.h" #include "archives.h"
#include "file.h" #include "file.h"
@@ -18,7 +17,7 @@ error_t install_addMod(char * filePath, int appId) {
goto exit; goto exit;
} }
char * configFolder = g_build_filename(getenv("HOME"), MODLIB_WORKING_DIR, NULL); char * configFolder = g_build_filename(getenv("HOME"), MANAGER_FILES, NULL);
if(g_mkdir_with_parents(configFolder, 0755) < 0) { if(g_mkdir_with_parents(configFolder, 0755) < 0) {
fprintf(stderr, "Could not create mod folder"); fprintf(stderr, "Could not create mod folder");
resultError = ERR_FAILURE; resultError = ERR_FAILURE;
+1 -3
View File
@@ -1,9 +1,7 @@
#ifndef __INSTALL_H__ #ifndef __INSTALL_H__
#define __INSTALL_H__ #define __INSTALL_H__
#include <stdlib.h> #include <stdlib.h>
#include <errorType.h> #include "main.h"
#define INSTALLED_FLAG_FILE "__DO_NOT_REMOVE__" #define INSTALLED_FLAG_FILE "__DO_NOT_REMOVE__"
/** /**
-109
View File
@@ -1,109 +0,0 @@
#include <stdlib.h>
#include <sys/mount.h>
#include <unistd.h>
#include <errorType.h>
#include <deploy.h>
#include <steam.h>
#include <constants.h>
#include "gameData.h"
#include "getHome.h"
#include "file.h"
#include "order.h"
#include "overlayfs.h"
#include "install.h"
deploymentErrors_t deploy(char * appIdStr, GList ** ignoredMods) {
int appid = steam_parseAppId(appIdStr);
if(appid < 0) {
return INVALID_APPID;
}
char * home = getHome();
char * gameFolder = g_build_filename(home, MODLIB_WORKING_DIR, GAME_FOLDER_NAME, appIdStr, NULL);
//is the game present in the disk
if(access(gameFolder, F_OK) != 0) {
free(home);
g_free(gameFolder);
return GAME_NOT_FOUND;
}
char * dataFolder = NULL;
error_t error = gameData_getDataPath(appid, &dataFolder);
if(error != ERR_SUCCESS) {
free(home);
return GAME_NOT_FOUND;
}
//unmount everything beforhand
//might crash if no mods were installed
char * modFolder = g_build_filename(home, MODLIB_WORKING_DIR, MOD_FOLDER_NAME, appIdStr, NULL);
GList * mods = order_listMods(appid);
//since the priority is by alphabetical order
//and we need to bind the least important first
//and the most important last
//we have to reverse the list
mods = g_list_reverse(mods);
//probably over allocating but this doesn't matter that much
char * modsToInstall[g_list_length(mods) + 2];
int modCount = 0;
while(true) {
if(mods == NULL)break;
char * modName = (char *)mods->data;
char * modPath = g_build_path("/", modFolder, modName, NULL);
char * modFlag = g_build_filename(modPath, INSTALLED_FLAG_FILE, NULL);
//if the mod is not marked to be deployed then don't
if(access(modFlag, F_OK) != 0) {
*ignoredMods = g_list_append(*ignoredMods, modName);
mods = g_list_next(mods);
continue;
}
//this is made to leave the first case empty so i can put lowerdir in it before feeding it to g_strjoinv
modsToInstall[modCount] = modPath;
modCount += 1;
mods = g_list_next(mods);
free(modFlag);
}
g_free(modFolder);
//const char * data = "lowerdir=gameFolder,gameFolder2,gameFolder3..."
modsToInstall[modCount] = gameFolder;
modsToInstall[modCount + 1] = NULL;
char * gameUpperDir = g_build_filename(home, MODLIB_WORKING_DIR, GAME_UPPER_DIR_NAME, appIdStr, NULL);
char * gameWorkDir = g_build_filename(home, MODLIB_WORKING_DIR, GAME_WORK_DIR_NAME, appIdStr, NULL);
free(home);
//unmount the game folder
//DETACH + FORCE allow us to be sure it will be unload.
//it might crash / corrupt game file if the user do it while the game is running
//but it's still very unlikely
while(umount2(dataFolder, MNT_FORCE | MNT_DETACH) == 0);
overlay_errors_t status = overlay_mount(modsToInstall, dataFolder, gameUpperDir, gameWorkDir);
if(status == SUCESS) {
return OK;
} else if(status == FAILURE) {
return CANNOT_MOUNT;
} else if(status == NOT_INSTALLED) {
return FUSE_NOT_INSTALLED;
} else {
return BUG;
}
g_free(dataFolder);
g_free(gameUpperDir);
g_free(gameWorkDir);
return EXIT_SUCCESS;
}
-165
View File
@@ -1,165 +0,0 @@
#include <libxml/tree.h>
#include <libxml/parser.h>
#include <libxml/xmlstring.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <stdarg.h>
#include <unistd.h>
#include <fomod.h>
#include "file.h"
#include "libxml/globals.h"
#include <constants.h>
#include "fomod/group.h"
#include "fomod/xmlUtil.h"
static gint priorityCmp(gconstpointer a, gconstpointer b) {
const fomod_File_t * fileA = (const fomod_File_t *)a;
const fomod_File_t * fileB = (const fomod_File_t *)b;
return fileB->priority - fileA->priority;
}
//match the definirion of gcompare func
static gint fomod_flagEqual(const fomod_Flag_t * a, const fomod_Flag_t * b) {
int nameCmp = strcmp(a->name, b->name);
if(nameCmp == 0) {
if(strcmp(a->value, b->value) == 0)
//is equal
return 0;
return 1;
}
return nameCmp;
}
//TODO: handle error
error_t fomod_processFileOperations(GList ** pendingFileOperations, const char * modFolder, const char * destination) {
//priority higher a less important and should be processed first.
*pendingFileOperations = g_list_sort(*pendingFileOperations, priorityCmp);
GList * currentFileOperation = *pendingFileOperations;
while(currentFileOperation != NULL) {
//TODO: support destination
//no using link since priority is made to override files and link is annoying to deal with when overriding files.
const fomod_File_t * file = (const fomod_File_t *)currentFileOperation->data;
char * source = g_build_path("/", modFolder, file->source, NULL);
//fix the / and \ windows - unix paths
xml_fixPath(source);
int copyResult;
if(file->isFolder) {
copyResult = file_copy(source, destination, FILE_CP_NO_TARGET_DIR | FILE_CP_RECURSIVE);
} else {
copyResult = file_copy(source, destination, 0);
}
if(copyResult != EXIT_SUCCESS) {
fprintf(stderr, "Copy failed, some file might be corrupted\n");
}
g_free(source);
currentFileOperation = g_list_next(currentFileOperation);
}
return ERR_SUCCESS;
}
GList * fomod_processCondFiles(const FOMod_t * fomod, GList * flagList, GList * pendingFileOperations) {
for(int condId = 0; condId < fomod->condFilesCount; condId++) {
const fomod_CondFile_t *condFile = &fomod->condFiles[condId];
bool areAllFlagsValid = true;
//checking if all flags are valid
for(long flagId = 0; flagId < condFile->flagCount; flagId++) {
const GList * link = g_list_find_custom(flagList, &(condFile->requiredFlags[flagId]), (GCompareFunc)fomod_flagEqual);
if(link == NULL) {
areAllFlagsValid = false;
break;
}
}
if(areAllFlagsValid) {
for(long fileId = 0; fileId < condFile->flagCount; fileId++) {
const fomod_File_t * file = &(condFile->files[fileId]);
fomod_File_t * fileCopy = malloc(sizeof(*file));
*fileCopy = *file;
//changing pathes to lowercase since we used casefold and the pathes in the xml might not like it
char * destination = g_ascii_strdown(file->destination, -1);
fileCopy->destination = destination;
char * source = g_ascii_strdown(file->source, -1);
fileCopy->source = source;
pendingFileOperations = g_list_append(pendingFileOperations, fileCopy);
}
}
}
return pendingFileOperations;
}
void fomod_freeFileOperations(GList * fileOperations) {
GList * fileOperationsStart = fileOperations;
while(fileOperations != NULL) {
fomod_File_t * file = (fomod_File_t *)fileOperations->data;
if(file->destination != NULL)free(file->destination);
if(file->source != NULL)free(file->source);
fileOperations = g_list_next(fileOperations);
}
g_list_free_full(fileOperationsStart, free);
}
void fomod_freeFOMod(FOMod_t * fomod) {
for(int i = 0; i < fomod->condFilesCount; i++) {
fomod_CondFile_t * condFile = &(fomod->condFiles[i]);
for(long fileId = 0; fileId < condFile->fileCount; fileId++) {
free(condFile->files[fileId].destination);
free(condFile->files[fileId].source);
}
for(long flagId = 0; flagId < condFile->flagCount; flagId++) {
fomod_Flag_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 = fomod_countUntilNull(fomod->requiredInstallFiles, sizeof(char **));
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++) {
fomod_Group_t * group = &step->groups[groupId];
grp_freeGroup(group);
}
for(int flagId = 0; flagId < step->flagCount; flagId++) {
fomod_Flag_t * flag = &(step->requiredFlags[flagId]);
free(flag->name);
free(flag->value);
}
free(step->groups);
free(step->requiredFlags);
free(step->name);
}
free(fomod->steps);
//set every counter to zero and every pointer to null
memset(fomod, 0, sizeof(FOMod_t));
}
-11
View File
@@ -1,11 +0,0 @@
#ifndef __GROUP_H__
#define __GROUP_H__
#include <libxml/parser.h>
#include "xmlUtil.h"
#include <fomod.h>
int grp_parseGroup(xmlNodePtr groupNode, fomod_Group_t* group);
void grp_freeGroup(fomod_Group_t * group);
#endif
+3 -4
View File
@@ -1,6 +1,5 @@
#include <constants.h>
#include "loadOrder.h" #include "loadOrder.h"
#include "main.h"
#include "steam.h" #include "steam.h"
#include "file.h" #include "file.h"
@@ -9,7 +8,7 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include "gameData.h" #include "getDataPath.h"
//TODO: detect if the game is running //TODO: detect if the game is running
//TODO: deploy the game //TODO: deploy the game
@@ -22,7 +21,7 @@ error_t order_listPlugins(int appid, GList ** plugins) {
sprintf(appidStr, "%d", appid); sprintf(appidStr, "%d", appid);
char * dataFolder = NULL; char * dataFolder = NULL;
error_t error = gameData_getDataPath(appid, &dataFolder); error_t error = getDataPath(appid, &dataFolder);
if(error != ERR_SUCCESS) { if(error != ERR_SUCCESS) {
return ERR_FAILURE; return ERR_FAILURE;
} }
+1 -1
View File
@@ -2,7 +2,7 @@
#define __LOAD_ORDER_H__ #define __LOAD_ORDER_H__
#include <glib.h> #include <glib.h>
#include <errorType.h> #include "main.h"
/** /**
* @brief find all plugins in the data folder of the game * @brief find all plugins in the data folder of the game
View File
+175 -62
View File
@@ -8,24 +8,20 @@
#include <sys/wait.h> #include <sys/wait.h>
#include <libaudit.h> #include <libaudit.h>
#include <gameData.h> #include "getDataPath.h"
#include <loadOrder.h> #include "loadOrder.h"
#include <deploy.h> #include "overlayfs.h"
#include <steam.h> #include "install.h"
#include <install.h> #include "getHome.h"
#include <getHome.h> #include "steam.h"
#include <steam.h> #include "main.h"
#include <file.h> #include "file.h"
#include <fomod.h>
#include <order.h>
#include <constants.h>
#include <deploy.h>
#include <errorType.h>
#include "cli.h"
#include "fomod.h" #include "fomod.h"
#include "order.h"
#include "gui/guiMain.h"
GHashTable * gamePaths;
#define ENABLED_COLOR "\033[0;32m" #define ENABLED_COLOR "\033[0;32m"
#define DISABLED_COLOR "\033[0;31m" #define DISABLED_COLOR "\033[0;31m"
@@ -33,6 +29,24 @@ static bool isRoot() {
return getuid() == 0; return getuid() == 0;
} }
static GList * listFilesInFolder(const char * path) {
GList * list = NULL;
DIR *d;
struct dirent *dir;
d = opendir(path);
if (d) {
while ((dir = readdir(d)) != NULL) {
//removes .. & . from the list
if(strcmp(dir->d_name, "..") != 0 && strcmp(dir->d_name, ".") != 0) {
list = g_list_append(list, strdup(dir->d_name));
}
}
closedir(d);
}
return list;
}
static int usage() { static int usage() {
printf("Use --list-games or -l to list compatible games\n"); printf("Use --list-games or -l to list compatible games\n");
@@ -56,6 +70,36 @@ static int usage() {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
static error_t validateAppId(const char * appIdStr) {
GHashTable * gamePaths;
error_t status = steam_searchGames(&gamePaths);
if(status == ERR_FAILURE) {
return ERR_FAILURE;
}
char * strtoulSentinel;
//strtoul set EINVAL(after C99) if the string is invalid
unsigned long appid = strtoul(appIdStr, &strtoulSentinel, 10);
if(errno == EINVAL || strtoulSentinel == appIdStr) {
fprintf(stderr, "Appid has to be a valid number\n");
return -1;
}
int gameId = steam_gameIdFromAppId((int)appid);
if(gameId < 0) {
fprintf(stderr, "Game is not compatible\n");
return -1;
}
if(!g_hash_table_contains(gamePaths, &gameId)) {
fprintf(stderr, "Game not found\n");
return -1;
}
//no valid appid goes far enough to justify long
return (int)appid;
}
static int listGames(int argc, char **) { static int listGames(int argc, char **) {
if(argc != 2) return usage(); if(argc != 2) return usage();
@@ -84,7 +128,7 @@ static int add(int argc, char ** argv) {
if(argc != 4) return usage(); if(argc != 4) return usage();
const char * appIdStr = argv[2]; const char * appIdStr = argv[2];
int appid = steam_parseAppId(appIdStr); int appid = validateAppId(appIdStr);
if(appid < 0) { if(appid < 0) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@@ -96,14 +140,14 @@ static int add(int argc, char ** argv) {
static int listAllMods(int argc, char ** argv) { static int listAllMods(int argc, char ** argv) {
if(argc != 3) return usage(); if(argc != 3) return usage();
char * appIdStr = argv[2]; char * appIdStr = argv[2];
int appid = steam_parseAppId(appIdStr); int appid = validateAppId(appIdStr);
if( appid < 0) { if( appid < 0) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
//might crash if no mods were installed //might crash if no mods were installed
char * home = getHome(); char * home = getHome();
char * modFolder = g_build_filename(home, MODLIB_WORKING_DIR, MOD_FOLDER_NAME, appIdStr, NULL); char * modFolder = g_build_filename(home, MANAGER_FILES, MOD_FOLDER_NAME, appIdStr, NULL);
free(home); free(home);
GList * mods = order_listMods(appid); GList * mods = order_listMods(appid);
@@ -142,7 +186,7 @@ static int listAllMods(int argc, char ** argv) {
static int installAndUninstallMod(int argc, char ** argv, bool install) { static int installAndUninstallMod(int argc, char ** argv, bool install) {
if(argc != 4) return usage(); if(argc != 4) return usage();
char * appIdStr = argv[2]; char * appIdStr = argv[2];
int appid = steam_parseAppId(appIdStr); int appid = validateAppId(appIdStr);
if(appid < 0) { if(appid < 0) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
@@ -158,9 +202,9 @@ static int installAndUninstallMod(int argc, char ** argv, bool install) {
//might crash if no mods were installed //might crash if no mods were installed
char * home = getHome(); char * home = getHome();
char * modFolder = g_build_filename(home, MODLIB_WORKING_DIR, MOD_FOLDER_NAME, appIdStr, NULL); char * modFolder = g_build_filename(home, MANAGER_FILES, MOD_FOLDER_NAME, appIdStr, NULL);
free(home); free(home);
GList * mods = order_listMods(appid); GList * mods = listFilesInFolder(modFolder);
GList * modsFirstPointer = mods; GList * modsFirstPointer = mods;
for(unsigned long i = 0; i < modId; i++) { for(unsigned long i = 0; i < modId; i++) {
@@ -214,63 +258,129 @@ exit:
return returnValue; return returnValue;
} }
static error_t cli_deploy(int argc, char ** argv) { static int deploy(int argc, char ** argv) {
if(argc != 3) return usage(); if(argc != 3) return usage();
char * appIdStr = argv[2]; char * appIdStr = argv[2];
int appid = steam_parseAppId(appIdStr); int appid = validateAppId(appIdStr);
if(appid < 0) { if(appid < 0) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
GList * ignoredMods = NULL; char * home = getHome();
char * gameFolder = g_build_filename(home, MANAGER_FILES, GAME_FOLDER_NAME, appIdStr, NULL);
deploymentErrors_t errors = deploy(appIdStr, &ignoredMods); if(access(gameFolder, F_OK) != 0) {
switch(errors) { free(home);
//we prevalidate the appid so it is a bug g_free(gameFolder);
default: printf("Please run '%s --setup %d' first", APP_NAME, appid);
case INVALID_APPID: return EXIT_FAILURE;
case BUG:
fprintf(stderr, "A bug was detected during the deployment\n");
return ERR_FAILURE;
case CANNOT_MOUNT:
fprintf(stderr, "Failed to mount the game files");
return ERR_FAILURE;
case FUSE_NOT_INSTALLED:
fprintf(stderr, "This software requires fuse-overlayfs to be installed");
return ERR_FAILURE;
case GAME_NOT_FOUND:
fprintf(stderr, "Could not find the game files");
return ERR_FAILURE;
case OK:
printf("Success");
return ERR_SUCCESS;
} }
//unmount everything beforhand
//might crash if no mods were installed
char * modFolder = g_build_filename(home, MANAGER_FILES, MOD_FOLDER_NAME, appIdStr, NULL);
GList * mods = listFilesInFolder(modFolder);
//since the priority is by alphabetical order
//and we need to bind the least important first
//and the most important last
//we have to reverse the list
mods = g_list_reverse(mods);
//probably over allocating but this doesn't matter that much
char * modsToInstall[g_list_length(mods) + 2];
int modCount = 0;
while(true) {
if(mods == NULL)break;
char * modName = (char *)mods->data;
char * modPath = g_build_path("/", modFolder, modName, NULL);
char * modFlag = g_build_filename(modPath, INSTALLED_FLAG_FILE, NULL);
//if the mod is not marked to be deployed then don't
if(access(modFlag, F_OK) != 0) {
printf("ignoring mod %s\n", modName);
mods = g_list_next(mods);
continue;
}
//this is made to leave the first case empty so i can put lowerdir in it before feeding it to g_strjoinv
printf("Installing %s\n", modName);
modsToInstall[modCount] = modPath;
modCount += 1;
mods = g_list_next(mods);
free(modFlag);
}
g_free(modFolder);
//const char * data = "lowerdir=gameFolder,gameFolder2,gameFolder3..."
modsToInstall[modCount] = gameFolder;
modsToInstall[modCount + 1] = NULL;
printf("Mounting the overlay\n");
char * dataFolder = NULL;
error_t error = getDataPath(appid, &dataFolder);
if(error != ERR_SUCCESS) {
free(home);
return ERR_FAILURE;
}
char * gameUpperDir = g_build_filename(home, MANAGER_FILES, GAME_UPPER_DIR_NAME, appIdStr, NULL);
char * gameWorkDir = g_build_filename(home, MANAGER_FILES, GAME_WORK_DIR_NAME, appIdStr, NULL);
free(home);
//unmount the game folder
//DETACH + FORCE allow us to be sure it will be unload.
//it might crash / corrupt game file if the user do it while the game is running
//but it's still very unlikely
while(umount2(dataFolder, MNT_FORCE | MNT_DETACH) == 0);
overlay_errors_t status = overlay_mount(modsToInstall, dataFolder, gameUpperDir, gameWorkDir);
if(status == SUCESS) {
printf("Everything is ready, just launch the game\n");
} else if(status == FAILURE) {
fprintf(stderr, "Could not mount the mods overlay\n");
return EXIT_FAILURE;
} else if(status == NOT_INSTALLED) {
fprintf(stderr, "Please install fuse-overlayfs\n");
return EXIT_FAILURE;
} else {
fprintf(stderr, "%d bug detected, please report this.\n", __LINE__);
return EXIT_FAILURE;
}
g_free(dataFolder);
g_free(gameUpperDir);
g_free(gameWorkDir);
return EXIT_SUCCESS;
} }
static int setup(int argc, char ** argv) { static int setup(int argc, char ** argv) {
if(argc != 3 ) return usage(); if(argc != 3 ) return usage();
const char * appIdStr = argv[2]; const char * appIdStr = argv[2];
int appid = steam_parseAppId(appIdStr); int appid = validateAppId(appIdStr);
if(appid < 0) { if(appid < 0) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
char * home = getHome(); char * home = getHome();
char * gameUpperDir = g_build_filename(home, MODLIB_WORKING_DIR, GAME_UPPER_DIR_NAME, appIdStr, NULL); char * gameUpperDir = g_build_filename(home, MANAGER_FILES, GAME_UPPER_DIR_NAME, appIdStr, NULL);
char * gameWorkDir = g_build_filename(home, MODLIB_WORKING_DIR, GAME_WORK_DIR_NAME, appIdStr, NULL); char * gameWorkDir = g_build_filename(home, MANAGER_FILES, GAME_WORK_DIR_NAME, appIdStr, NULL);
g_mkdir_with_parents(gameUpperDir, 0755); g_mkdir_with_parents(gameUpperDir, 0755);
g_mkdir_with_parents(gameWorkDir, 0755); g_mkdir_with_parents(gameWorkDir, 0755);
free(gameUpperDir); free(gameUpperDir);
free(gameWorkDir); free(gameWorkDir);
char * dataFolder = NULL; char * dataFolder = NULL;
error_t error = gameData_getDataPath(appid, &dataFolder); error_t error = getDataPath(appid, &dataFolder);
if(error != ERR_SUCCESS) { if(error != ERR_SUCCESS) {
return ERR_FAILURE; return ERR_FAILURE;
} }
char * gameFolder = g_build_filename(home, MODLIB_WORKING_DIR, GAME_FOLDER_NAME, appIdStr, NULL); char * gameFolder = g_build_filename(home, MANAGER_FILES, GAME_FOLDER_NAME, appIdStr, NULL);
if(access(gameFolder, F_OK) == 0) { if(access(gameFolder, F_OK) == 0) {
//if the game folder alredy exists just delete it //if the game folder alredy exists just delete it
//this will allow the removal of dlcs and language change //this will allow the removal of dlcs and language change
@@ -303,13 +413,13 @@ static int setup(int argc, char ** argv) {
static int unbind(int argc, char ** argv) { static int unbind(int argc, char ** argv) {
if(argc != 3 ) return usage(); if(argc != 3 ) return usage();
const char * appIdStr = argv[2]; const char * appIdStr = argv[2];
int appid = steam_parseAppId(appIdStr); int appid = validateAppId(appIdStr);
if(appid < 0) { if(appid < 0) {
return EXIT_FAILURE; return EXIT_FAILURE;
} }
char * dataFolder = NULL; char * dataFolder = NULL;
error_t error = gameData_getDataPath(appid, &dataFolder); error_t error = getDataPath(appid, &dataFolder);
if(error != ERR_SUCCESS) { if(error != ERR_SUCCESS) {
return ERR_FAILURE; return ERR_FAILURE;
} }
@@ -323,7 +433,7 @@ static int unbind(int argc, char ** argv) {
static int removeMod(int argc, char ** argv) { static int removeMod(int argc, char ** argv) {
if(argc != 4) return usage(); if(argc != 4) return usage();
const char * appIdStr = argv[2]; const char * appIdStr = argv[2];
int appid = steam_parseAppId(appIdStr); int appid = validateAppId(appIdStr);
if(appid < 0) { if(appid < 0) {
fprintf(stderr, "Invalid appid"); fprintf(stderr, "Invalid appid");
return EXIT_FAILURE; return EXIT_FAILURE;
@@ -338,9 +448,9 @@ static int removeMod(int argc, char ** argv) {
//might crash if no mods were installed //might crash if no mods were installed
char * home = getHome(); char * home = getHome();
char * modFolder = g_build_filename(home, MODLIB_WORKING_DIR, MOD_FOLDER_NAME, appIdStr, NULL); char * modFolder = g_build_filename(home, MANAGER_FILES, MOD_FOLDER_NAME, appIdStr, NULL);
free(home); free(home);
GList * mods = order_listMods(appid); GList * mods = listFilesInFolder(modFolder);
GList * modsFirstPointer = mods; GList * modsFirstPointer = mods;
for(unsigned long i = 0; i < modId; i++) { for(unsigned long i = 0; i < modId; i++) {
@@ -365,7 +475,7 @@ static int removeMod(int argc, char ** argv) {
static int fomod(int argc, char ** argv) { static int fomod(int argc, char ** argv) {
if(argc != 4) return usage(); if(argc != 4) return usage();
char * appIdStr = argv[2]; char * appIdStr = argv[2];
int appid = steam_parseAppId(appIdStr); int appid = validateAppId(appIdStr);
if(appid < 0) { if(appid < 0) {
fprintf(stderr, "Invalid appid"); fprintf(stderr, "Invalid appid");
return EXIT_FAILURE; return EXIT_FAILURE;
@@ -380,9 +490,9 @@ static int fomod(int argc, char ** argv) {
//might crash if no mods were installed //might crash if no mods were installed
char * home = getHome(); char * home = getHome();
char * modFolder = g_build_filename(home, MODLIB_WORKING_DIR, MOD_FOLDER_NAME, appIdStr, NULL); char * modFolder = g_build_filename(home, MANAGER_FILES, MOD_FOLDER_NAME, appIdStr, NULL);
free(home); free(home);
GList * mods = order_listMods(appid); GList * mods = listFilesInFolder(modFolder);
GList * modsFirstPointer = mods; GList * modsFirstPointer = mods;
for(unsigned long i = 0; i < modId; i++) { for(unsigned long i = 0; i < modId; i++) {
@@ -416,7 +526,7 @@ static int fomod(int argc, char ** argv) {
static int swapMod(int argc, char ** argv) { static int swapMod(int argc, char ** argv) {
if(argc != 5) return usage(); if(argc != 5) return usage();
char * appIdStr = argv[2]; char * appIdStr = argv[2];
int appid = steam_parseAppId(appIdStr); int appid = validateAppId(appIdStr);
if(appid < 0) { if(appid < 0) {
fprintf(stderr, "Invalid appid"); fprintf(stderr, "Invalid appid");
return EXIT_FAILURE; return EXIT_FAILURE;
@@ -444,7 +554,7 @@ static int printLoadOrder(int argc, char ** argv) {
if(argc != 3) return usage(); if(argc != 3) return usage();
char * appIdStr = argv[2]; char * appIdStr = argv[2];
int appid = steam_parseAppId(appIdStr); int appid = validateAppId(appIdStr);
if(appid < 0) { if(appid < 0) {
fprintf(stderr, "Invalid appid"); fprintf(stderr, "Invalid appid");
return EXIT_FAILURE; return EXIT_FAILURE;
@@ -473,7 +583,7 @@ static int printPlugins(int argc, char ** argv) {
if(argc != 3) return usage(); if(argc != 3) return usage();
char * appIdStr = argv[2]; char * appIdStr = argv[2];
int appid = steam_parseAppId(appIdStr); int appid = validateAppId(appIdStr);
if(appid < 0) { if(appid < 0) {
fprintf(stderr, "Invalid appid"); fprintf(stderr, "Invalid appid");
return EXIT_FAILURE; return EXIT_FAILURE;
@@ -506,7 +616,7 @@ int main(int argc, char ** argv) {
int returnValue = EXIT_SUCCESS; int returnValue = EXIT_SUCCESS;
char * home = getHome(); char * home = getHome();
char * configFolder = g_build_filename(home, MODLIB_WORKING_DIR, NULL); char * configFolder = g_build_filename(home, MANAGER_FILES, NULL);
free(home); free(home);
if(access(configFolder, F_OK) != 0) { if(access(configFolder, F_OK) != 0) {
@@ -544,7 +654,7 @@ int main(int argc, char ** argv) {
returnValue = installAndUninstallMod(argc, argv, false); returnValue = installAndUninstallMod(argc, argv, false);
else if(strcmp(argv[1], "--bind") == 0 || strcmp(argv[1], "-d") == 0) else if(strcmp(argv[1], "--bind") == 0 || strcmp(argv[1], "-d") == 0)
returnValue = cli_deploy(argc, argv); returnValue = deploy(argc, argv);
else if(strcmp(argv[1], "--unbind") == 0) else if(strcmp(argv[1], "--unbind") == 0)
returnValue = unbind(argc, argv); returnValue = unbind(argc, argv);
@@ -558,6 +668,9 @@ int main(int argc, char ** argv) {
else if(strcmp(argv[1], "--remove") == 0 || strcmp(argv[1], "-r") == 0) else if(strcmp(argv[1], "--remove") == 0 || strcmp(argv[1], "-r") == 0)
returnValue = removeMod(argc, argv); returnValue = removeMod(argc, argv);
else if(strcmp(argv[1], "--gui") == 0)
returnValue = guiMain(argc, argv);
else if(strcmp(argv[1], "--swap") == 0 || strcmp(argv[1], "-s") == 0) else if(strcmp(argv[1], "--swap") == 0 || strcmp(argv[1], "-s") == 0)
returnValue = swapMod(argc, argv); returnValue = swapMod(argc, argv);
+8 -3
View File
@@ -1,12 +1,14 @@
#ifndef __MAIN_H__ #ifndef __MAIN_H__
#define __MAIN_H__ #define __MAIN_H__
#define MODLIB_NAME "mod-manager" #include <glib.h>
//no function should ever be put here, only keep important macros and globals here //no function should ever be put here, only keep important macros and globals here
#define APP_NAME "mod-manager"
//relative to home the url is not preprocessed so ../ might create some issues //relative to home the url is not preprocessed so ../ might create some issues
// in c "A" "B" is the same as "AB" // in c "A" "B" is the same as "AB"
#define MODLIB_WORKING_DIR ".local/share/" MODLIB_NAME #define MANAGER_FILES ".local/share/" APP_NAME
#define MOD_FOLDER_NAME "MOD_FOLDER" #define MOD_FOLDER_NAME "MOD_FOLDER"
//the folder in which the games file will be linked or copied //the folder in which the games file will be linked or copied
#define GAME_FOLDER_NAME "GAME_FOLDER" #define GAME_FOLDER_NAME "GAME_FOLDER"
@@ -15,5 +17,8 @@
//overlayfs temporary dir. //overlayfs temporary dir.
#define GAME_WORK_DIR_NAME "WORK_DIRS" #define GAME_WORK_DIR_NAME "WORK_DIRS"
#define MODLIB_VERSION "0.1" #define VERSION "0.1"
typedef enum { ERR_SUCCESS, ERR_FAILURE } error_t;
#endif #endif
+3 -4
View File
@@ -3,8 +3,7 @@
#include "order.h" #include "order.h"
//no function are declared in main it's just macros //no function are declared in main it's just macros
#include <constants.h> #include "main.h"
#include "getHome.h" #include "getHome.h"
typedef struct Mod { typedef struct Mod {
@@ -28,7 +27,7 @@ GList * order_listMods(int appid) {
sprintf(appidStr, "%d", appid); sprintf(appidStr, "%d", appid);
char * home = getHome(); char * home = getHome();
char * modFolder = g_build_filename(home, MODLIB_WORKING_DIR, MOD_FOLDER_NAME, appidStr, NULL); char * modFolder = g_build_filename(home, MANAGER_FILES, MOD_FOLDER_NAME, appidStr, NULL);
free(home); free(home);
GList * list = NULL; GList * list = NULL;
@@ -100,7 +99,7 @@ error_t order_swapPlace(int appid, int modIdA, int modIdB) {
sprintf(appidStr, "%d", appid); sprintf(appidStr, "%d", appid);
char * home = getHome(); char * home = getHome();
char * modFolder = g_build_filename(home, MODLIB_WORKING_DIR, MOD_FOLDER_NAME, appidStr, NULL); char * modFolder = g_build_filename(home, MANAGER_FILES, MOD_FOLDER_NAME, appidStr, NULL);
free(home); free(home);
GList * list = order_listMods(appid); GList * list = order_listMods(appid);
+1 -1
View File
@@ -2,7 +2,7 @@
#define __ORDER_H__ #define __ORDER_H__
#include <glib.h> #include <glib.h>
#include <errorType.h> #include "main.h"
#define ORDER_FILE "__ORDER__" #define ORDER_FILE "__ORDER__"
+1 -1
View File
@@ -16,7 +16,7 @@ overlay_errors_t overlay_mount(char ** sources, const char * dest, const char *
int pid = fork(); int pid = fork();
if(pid == 0) { if(pid == 0) {
//exit is used to get the return value when using waitpid //exit is used to get the return value when using waitpid
exit(execl("/usr/bin/fuse-overlayfs", "/usr/bin/fuse-overlayfs", "-o", mountData, dest, NULL)); exit(execl("/usr/bin/fuse-overlayfs", "/usr/bin/fuse-overlayfs", "-r", "-o", mountData, dest, NULL));
} else { } else {
int returnValue = 0; int returnValue = 0;
+1 -33
View File
@@ -1,9 +1,7 @@
#include "steam.h" #include "steam.h"
#include "macro.h" #include "macro.h"
#include "getHome.h" #include "getHome.h"
#include "main.h"
#include <constants.h>
#include <unistd.h> #include <unistd.h>
#include <stddef.h> #include <stddef.h>
#include <stdio.h> #include <stdio.h>
@@ -257,33 +255,3 @@ int steam_gameIdFromAppId(u_int32_t appid) {
} }
return -1; return -1;
} }
int steam_parseAppId(const char * appIdStr) {
GHashTable * gamePaths;
error_t status = steam_searchGames(&gamePaths);
if(status == ERR_FAILURE) {
return -1;
}
char * strtoulSentinel;
//strtoul set EINVAL(after C99) if the string is invalid
unsigned long appid = strtoul(appIdStr, &strtoulSentinel, 10);
if(errno == EINVAL || strtoulSentinel == appIdStr) {
fprintf(stderr, "Appid has to be a valid number\n");
return -1;
}
int gameId = steam_gameIdFromAppId((int)appid);
if(gameId < 0) {
fprintf(stderr, "Game is not compatible\n");
return -1;
}
if(!g_hash_table_contains(gamePaths, &gameId)) {
fprintf(stderr, "Game not found\n");
return -1;
}
//no valid appid goes far enough to justify long
return (int)appid;
}
+6 -11
View File
@@ -1,12 +1,14 @@
#ifndef __STEAM_H__ #ifndef __STEAM_H__
#define __STEAM_H__ #define __STEAM_H__
#include "macro.h"
#include "main.h"
#include <stdbool.h> #include <stdbool.h>
#include <stddef.h> #include <stddef.h>
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <glib.h> #include <glib.h>
#include <errorType.h>
typedef struct steam_App { typedef struct steam_App {
unsigned int appid; unsigned int appid;
@@ -30,6 +32,7 @@ static const u_int32_t GAMES_APPIDS[] = {
489830, 489830,
22330, 22330,
377160, 377160,
72850,
22320 22320
}; };
@@ -38,11 +41,11 @@ static const char * GAMES_NAMES[] = {
"Skyrim Special Edition", "Skyrim Special Edition",
"Oblivion", "Oblivion",
"Fallout 4", "Fallout 4",
"Skyrim",
"Morrowind" "Morrowind"
}; };
_Static_assert(sizeof(GAMES_NAMES) / sizeof(GAMES_NAMES[0]) == sizeof(GAMES_APPIDS) / sizeof(GAMES_APPIDS[0]), _Static_assert(LEN(GAMES_APPIDS) == LEN(GAMES_NAMES), "Game APPIDS and Game Names doesn't match");
"Game APPIDS and Game Names doesn't match");
/** /**
* @brief list all installed games and the paths to the game's files * @brief list all installed games and the paths to the game's files
@@ -63,12 +66,4 @@ void steam_freeGameTable(void);
*/ */
int steam_gameIdFromAppId(u_int32_t appid); int steam_gameIdFromAppId(u_int32_t appid);
/**
* @brief Parse the steamId string
*
* @param appIdStr steamId string
* @return int -1 if failures or an int containing the steamId
*/
int steam_parseAppId(const char * appIdStr);
#endif #endif