Merged master into interface
This commit is contained in:
@@ -0,0 +1,36 @@
|
|||||||
|
# This file is a template, and might need editing before it works on your project.
|
||||||
|
# To contribute improvements to CI/CD templates, please follow the Development guide at:
|
||||||
|
# https://docs.gitlab.com/ee/development/cicd/templates.html
|
||||||
|
# This specific template is located at:
|
||||||
|
# https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Getting-Started.gitlab-ci.yml
|
||||||
|
|
||||||
|
# This is a sample GitLab CI/CD configuration file that should run without any modifications.
|
||||||
|
# It demonstrates a basic 3 stage CI/CD pipeline. Instead of real tests or scripts,
|
||||||
|
# it uses echo commands to simulate the pipeline execution.
|
||||||
|
#
|
||||||
|
# A pipeline is composed of independent jobs that run scripts, grouped into stages.
|
||||||
|
# Stages run in sequential order, but jobs within stages run in parallel.
|
||||||
|
#
|
||||||
|
# For more information, see: https://docs.gitlab.com/ee/ci/yaml/index.html#stages
|
||||||
|
|
||||||
|
before_script:
|
||||||
|
- apt update -y
|
||||||
|
- apt install cmake libglib2.0-dev libgtk-4-dev make gcc git make clang libaudit-dev -y
|
||||||
|
|
||||||
|
|
||||||
|
stages: # List of stages for jobs, and their order of execution
|
||||||
|
- build
|
||||||
|
|
||||||
|
build-job: # This job runs in the build stage, which runs first.
|
||||||
|
stage: build
|
||||||
|
script:
|
||||||
|
- mkdir build
|
||||||
|
- cd build
|
||||||
|
- cmake ..
|
||||||
|
- make
|
||||||
|
- echo "Build done"
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- build/ModManager
|
||||||
|
expire_in: 1 week
|
||||||
|
|
||||||
+2
-2
@@ -9,7 +9,6 @@ project(ModManager)
|
|||||||
|
|
||||||
|
|
||||||
set(SOURCES
|
set(SOURCES
|
||||||
src/main.c
|
|
||||||
src/steam.c
|
src/steam.c
|
||||||
src/install.c
|
src/install.c
|
||||||
src/overlayfs.c
|
src/overlayfs.c
|
||||||
@@ -24,7 +23,8 @@ set(SOURCES
|
|||||||
)
|
)
|
||||||
|
|
||||||
# add the executable
|
# add the executable
|
||||||
add_executable(ModManager ${SOURCES})
|
add_executable(ModManager src/main.c ${SOURCES})
|
||||||
|
|
||||||
add_compile_options(-Wall -Wextra -pedantic -Werror)
|
add_compile_options(-Wall -Wextra -pedantic -Werror)
|
||||||
|
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
|
|||||||
+32
-1
@@ -4,13 +4,44 @@
|
|||||||
#ifndef __FILE_H__
|
#ifndef __FILE_H__
|
||||||
#define __FILE_H__
|
#define __FILE_H__
|
||||||
|
|
||||||
|
|
||||||
|
//valid copy flags
|
||||||
|
#define cp_DEFAULT 0
|
||||||
#define CP_LINK 1
|
#define CP_LINK 1
|
||||||
#define CP_RECURSIVE 2
|
#define CP_RECURSIVE 2
|
||||||
#define CP_NO_TARGET_DIR 4
|
#define CP_NO_TARGET_DIR 4
|
||||||
|
|
||||||
int copy(const char * path, const char * dest, u_int32_t flags);
|
/**
|
||||||
|
* @brief execute the cp command from the source to the dest
|
||||||
|
* @param source path to the source files
|
||||||
|
* @param dest path to the destination folder
|
||||||
|
* @param flags refer to the "valid copy flags" use them like this CP_LINK | CP_RECURSIVE
|
||||||
|
* @return status code
|
||||||
|
*/
|
||||||
|
int copy(const char * source, const char * dest, u_int32_t flags);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief execute the cp command from the source to the dest
|
||||||
|
* @param source path to the source files
|
||||||
|
* @param dest path to the destination folder
|
||||||
|
* @param bool enable recursive rm -r
|
||||||
|
* @return status code
|
||||||
|
*/
|
||||||
int delete(const char * path, bool recursive);
|
int delete(const char * path, bool recursive);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Run the mv command
|
||||||
|
* @param source
|
||||||
|
* @param destination
|
||||||
|
* @return mv's exit value
|
||||||
|
*/
|
||||||
int move(const char * source, const char * destination);
|
int move(const char * source, const char * destination);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Recursively rename all file and folder to lowercase.
|
||||||
|
*
|
||||||
|
* @param folder
|
||||||
|
*/
|
||||||
void casefold(const char * folder);
|
void casefold(const char * folder);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+74
-100
@@ -1,4 +1,3 @@
|
|||||||
#include "fomod.h"
|
|
||||||
#include <libxml/tree.h>
|
#include <libxml/tree.h>
|
||||||
#include <libxml/parser.h>
|
#include <libxml/parser.h>
|
||||||
#include <libxml/xmlstring.h>
|
#include <libxml/xmlstring.h>
|
||||||
@@ -8,11 +7,12 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
#include <glib.h>
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include "fomod.h"
|
||||||
#include "file.h"
|
#include "file.h"
|
||||||
#include "libxml/globals.h"
|
#include "libxml/globals.h"
|
||||||
#include "fomod/parser.h"
|
|
||||||
|
|
||||||
int getInputCount(const char * input) {
|
int getInputCount(const char * input) {
|
||||||
char buff[2];
|
char buff[2];
|
||||||
@@ -47,39 +47,6 @@ gint priorityCmp(gconstpointer a, gconstpointer b) {
|
|||||||
return fileA->priority - fileB->priority;
|
return fileA->priority - fileB->priority;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
char * findFOModFolder(const char * modFolder) {
|
|
||||||
struct dirent * dir;
|
|
||||||
DIR *d = opendir(modFolder);
|
|
||||||
if (d) {
|
|
||||||
while ((dir = readdir(d)) != NULL) {
|
|
||||||
if(g_ascii_strcasecmp(dir->d_name, "fomod") == 0) {
|
|
||||||
char * fomodDir = g_build_path("/", modFolder, dir->d_name, NULL);
|
|
||||||
closedir(d);
|
|
||||||
return fomodDir;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
closedir(d);
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
char * findFOModFile(const char * fomodFolder) {
|
|
||||||
struct dirent * dir;
|
|
||||||
DIR *d = opendir(fomodFolder);
|
|
||||||
if (d) {
|
|
||||||
while ((dir = readdir(d)) != NULL) {
|
|
||||||
if(g_ascii_strcasecmp(dir->d_name, "moduleconfig.xml") == 0) {
|
|
||||||
char * fomodFile = g_build_filename(fomodFolder, dir->d_name, NULL);
|
|
||||||
closedir(d);
|
|
||||||
return fomodFile;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
closedir(d);
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void printfOptionsInOrder(FOModGroup_t group) {
|
void printfOptionsInOrder(FOModGroup_t group) {
|
||||||
for(int i = 0; i < group.pluginCount; i++) {
|
for(int i = 0; i < group.pluginCount; i++) {
|
||||||
printf("%d, %s\n", i, group.plugins[i].name);
|
printf("%d, %s\n", i, group.plugins[i].name);
|
||||||
@@ -152,18 +119,75 @@ void sortGroup(FOModGroup_t * group) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO: support priority
|
//TODO: handle error
|
||||||
int installFOMod(const char * modFolder, const char * destination) {
|
int processFileOperations(GList * pendingFileOperations, const char * modFolder, const char * destination) {
|
||||||
char * fomodFolder = findFOModFolder(modFolder);
|
pendingFileOperations = g_list_sort(pendingFileOperations, priorityCmp);
|
||||||
if(fomodFolder == NULL) {
|
GList * currentFileOperation = pendingFileOperations;
|
||||||
fprintf(stderr, "Fomod folder not found, are you sure this is a fomod mod ?\n");
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
|
||||||
|
|
||||||
char * fomodFile = findFOModFile(fomodFolder);
|
while(currentFileOperation != NULL) {
|
||||||
if(fomodFile == 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 FOModFile_t * file = (const FOModFile_t *)currentFileOperation->data;
|
||||||
|
char * source = g_build_path("/", modFolder, file->source, NULL);
|
||||||
|
|
||||||
|
//fix the / and \ windows - unix paths
|
||||||
|
fixPath(source);
|
||||||
|
|
||||||
|
int copyResult;
|
||||||
|
if(file->isFolder) {
|
||||||
|
copyResult = copy(source, destination, CP_NO_TARGET_DIR | CP_RECURSIVE);
|
||||||
|
} else {
|
||||||
|
copyResult = copy(source, destination, 0);
|
||||||
|
}
|
||||||
|
if(copyResult != EXIT_SUCCESS) {
|
||||||
|
fprintf(stderr, "Copy failed, some file might be corrupted\n");
|
||||||
|
}
|
||||||
|
printf("source: %s, destination: %s\n", source, destination);
|
||||||
|
g_free(source);
|
||||||
|
|
||||||
|
currentFileOperation = g_list_next(currentFileOperation);
|
||||||
|
}
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
GList * processCondFiles(const FOMod_t * fomod, GList * flagList, GList * pendingFileOperations) {
|
||||||
|
for(int condId = 0; condId < fomod->condFilesCount; condId++) {
|
||||||
|
const FOModCondFile_t *condFile = &fomod->condFiles[condId];
|
||||||
|
|
||||||
|
bool areAllFlagsValid = true;
|
||||||
|
|
||||||
|
//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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(areAllFlagsValid) {
|
||||||
|
for(int fileId = 0; fileId < condFile->flagCount; fileId++) {
|
||||||
|
const FOModFile_t * file = &(condFile->files[fileId]);
|
||||||
|
|
||||||
|
FOModFile_t * fileCopy = malloc(sizeof(*file));
|
||||||
|
*fileCopy = *file;
|
||||||
|
|
||||||
|
pendingFileOperations = g_list_append(pendingFileOperations, fileCopy);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pendingFileOperations;
|
||||||
|
}
|
||||||
|
|
||||||
|
int 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");
|
fprintf(stderr, "FOMod file not found, are you sure this is a fomod mod ?\n");
|
||||||
g_free(fomodFolder);
|
g_free(fomodFolder);
|
||||||
|
g_free(fomodFile);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -172,6 +196,7 @@ int installFOMod(const char * modFolder, const char * destination) {
|
|||||||
if(returnValue != EXIT_SUCCESS) {
|
if(returnValue != EXIT_SUCCESS) {
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
g_free(fomodFile);
|
||||||
|
|
||||||
GList * flagList = NULL;
|
GList * flagList = NULL;
|
||||||
GList * pendingFileOperations = NULL;
|
GList * pendingFileOperations = NULL;
|
||||||
@@ -179,7 +204,7 @@ int installFOMod(const char * modFolder, const char * destination) {
|
|||||||
sortSteps(&fomod);
|
sortSteps(&fomod);
|
||||||
|
|
||||||
for(int i = 0; i < fomod.stepCount; i++) {
|
for(int i = 0; i < fomod.stepCount; i++) {
|
||||||
FOModStep_t * step = &fomod.steps[i];
|
const FOModStep_t * step = &fomod.steps[i];
|
||||||
|
|
||||||
bool validFlags = true;
|
bool validFlags = true;
|
||||||
for(int flagId = 0; flagId < step->flagCount; flagId++) {
|
for(int flagId = 0; flagId < step->flagCount; flagId++) {
|
||||||
@@ -280,66 +305,15 @@ int installFOMod(const char * modFolder, const char * destination) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int condId = 0; condId < fomod.condFilesCount; condId++) {
|
|
||||||
const FOModCondFile_t *condFile = &fomod.condFiles[condId];
|
|
||||||
|
|
||||||
bool areAllFlagsValid = true;
|
|
||||||
|
|
||||||
//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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(areAllFlagsValid) {
|
|
||||||
for(int fileId = 0; fileId < condFile->flagCount; fileId++) {
|
|
||||||
const FOModFile_t * file = &(condFile->files[fileId]);
|
|
||||||
|
|
||||||
FOModFile_t * fileCopy = malloc(sizeof(*file));
|
|
||||||
*fileCopy = *file;
|
|
||||||
|
|
||||||
pendingFileOperations = g_list_append(pendingFileOperations, fileCopy);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
pendingFileOperations = g_list_sort(pendingFileOperations, priorityCmp);
|
|
||||||
GList * currentFileOperation = pendingFileOperations;
|
|
||||||
|
|
||||||
while(currentFileOperation != NULL) {
|
|
||||||
//TODO: support destination
|
|
||||||
//TODO: handle error
|
|
||||||
//no using link since priority is made to override files and link is annoying to deal with when overriding files.
|
|
||||||
const FOModFile_t * file = (const FOModFile_t *)currentFileOperation->data;
|
|
||||||
char * source = g_build_path("/", modFolder, file->source, NULL);
|
|
||||||
|
|
||||||
//fix the / and \ windows - unix paths
|
|
||||||
fixPath(source);
|
|
||||||
|
|
||||||
int copyResult;
|
|
||||||
if(file->isFolder) {
|
|
||||||
copyResult = copy(source, destination, CP_NO_TARGET_DIR | CP_RECURSIVE);
|
|
||||||
} else {
|
|
||||||
copyResult = copy(source, destination, 0);
|
|
||||||
}
|
|
||||||
if(copyResult != EXIT_SUCCESS) {
|
|
||||||
fprintf(stderr, "Copy failed, some file might be corrupted\n");
|
|
||||||
}
|
|
||||||
printf("source: %s, destination: %s\n", source, destination);
|
|
||||||
g_free(source);
|
|
||||||
|
|
||||||
currentFileOperation = g_list_next(currentFileOperation);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
pendingFileOperations = processCondFiles(&fomod, flagList, pendingFileOperations);
|
||||||
|
processFileOperations(pendingFileOperations, modFolder, destination);
|
||||||
|
|
||||||
printf("FOMod successfully installed!\n");
|
printf("FOMod successfully installed!\n");
|
||||||
g_list_free(flagList);
|
g_list_free(flagList);
|
||||||
g_list_free_full(pendingFileOperations, free);
|
g_list_free_full(pendingFileOperations, free);
|
||||||
freeFOMod(&fomod);
|
freeFOMod(&fomod);
|
||||||
|
g_free(fomodFolder);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|||||||
+32
@@ -2,9 +2,41 @@
|
|||||||
#define __FOMOD_H__
|
#define __FOMOD_H__
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <glib.h>
|
||||||
|
#include "fomod/parser.h"
|
||||||
|
|
||||||
#include "fomod/group.h"
|
#include "fomod/group.h"
|
||||||
#include "fomod/xmlUtil.h"
|
#include "fomod/xmlUtil.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
|
||||||
|
*/
|
||||||
int installFOMod(const char * modFolder, const char * destination);
|
int 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.
|
||||||
|
*
|
||||||
|
* @param fomod a pointer to a fomod obtained by the parser
|
||||||
|
* @param flagList a FOModFlag_t list which contains all of the flag found.
|
||||||
|
* @param pendingFileOperations a list of pending FOModFile_t operation to which add the new ones. (can be null)
|
||||||
|
* @return a list of pendingFileOperations(FOModFile_t)
|
||||||
|
*/
|
||||||
|
GList * processCondFiles(const FOMod_t * fomod, GList * flagList, GList * pendingFileOperations) __attribute__((warn_unused_result));
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief FOModFile_t have a priority option and this function execute the file operation while taking this into account.
|
||||||
|
*
|
||||||
|
* @param pendingFileOperations list of FOModFile_t to process
|
||||||
|
* @param modFolder folder of the fomod file.
|
||||||
|
* @param destination folder of the new mod that contains the result of the process.
|
||||||
|
* @return error code
|
||||||
|
*/
|
||||||
|
int processFileOperations(GList * pendingFileOperations, const char * modFolder, const char * destination);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+6
-3
@@ -2,6 +2,7 @@
|
|||||||
#include "libxml/tree.h"
|
#include "libxml/tree.h"
|
||||||
#include "xmlUtil.h"
|
#include "xmlUtil.h"
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
//Maybe integrate this into the rest of the code instead of freeing after the fact
|
//Maybe integrate this into the rest of the code instead of freeing after the fact
|
||||||
void freeFOMod(FOMod_t * fomod) {
|
void freeFOMod(FOMod_t * fomod) {
|
||||||
@@ -21,11 +22,10 @@ void freeFOMod(FOMod_t * fomod) {
|
|||||||
free(condFile->requiredFlags);
|
free(condFile->requiredFlags);
|
||||||
}
|
}
|
||||||
free(fomod->condFiles);
|
free(fomod->condFiles);
|
||||||
|
|
||||||
free(fomod->moduleImage);
|
free(fomod->moduleImage);
|
||||||
free(fomod->moduleName);
|
free(fomod->moduleName);
|
||||||
|
|
||||||
int size = countUntilNull(fomod->requiredInstallFiles);
|
int size = countUntilNull(fomod->requiredInstallFiles, sizeof(char **));
|
||||||
for(int i = 0; i < size; i++) {
|
for(int i = 0; i < size; i++) {
|
||||||
free(fomod->requiredInstallFiles[i]);
|
free(fomod->requiredInstallFiles[i]);
|
||||||
}
|
}
|
||||||
@@ -46,6 +46,9 @@ void freeFOMod(FOMod_t * fomod) {
|
|||||||
free(step->requiredFlags);
|
free(step->requiredFlags);
|
||||||
free(step->name);
|
free(step->name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//set every counter to zero and every pointer to null
|
||||||
|
memset(fomod, 0, sizeof(FOMod_t));
|
||||||
}
|
}
|
||||||
|
|
||||||
int parseVisibleNode(xmlNodePtr node, FOModStep_t * step) {
|
int parseVisibleNode(xmlNodePtr node, FOModStep_t * step) {
|
||||||
@@ -285,7 +288,7 @@ int parseFOMod(const char * fomodFile, FOMod_t* fomod) {
|
|||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
int size = countUntilNull(fomod->requiredInstallFiles) + 2;
|
int size = countUntilNull(fomod->requiredInstallFiles, sizeof(char **)) + 2;
|
||||||
fomod->requiredInstallFiles = realloc(fomod->requiredInstallFiles, sizeof(char *) * size);
|
fomod->requiredInstallFiles = realloc(fomod->requiredInstallFiles, sizeof(char *) * size);
|
||||||
//ensure it is null terminated
|
//ensure it is null terminated
|
||||||
fomod->requiredInstallFiles[size - 1] = NULL;
|
fomod->requiredInstallFiles[size - 1] = NULL;
|
||||||
|
|||||||
@@ -25,7 +25,19 @@ typedef struct FOMod {
|
|||||||
int condFilesCount;
|
int condFilesCount;
|
||||||
} FOMod_t;
|
} 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
|
||||||
|
* @return error code.
|
||||||
|
*/
|
||||||
int parseFOMod(const char * fomodFile, FOMod_t* fomod);
|
int parseFOMod(const char * fomodFile, FOMod_t* fomod);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Free content of a fomod file.
|
||||||
|
* @param fomod
|
||||||
|
*/
|
||||||
void freeFOMod(FOMod_t * fomod);
|
void freeFOMod(FOMod_t * fomod);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+2
-2
@@ -27,10 +27,10 @@ void fixPath(char * path) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int countUntilNull(void * pointers) {
|
int countUntilNull(void * pointers, size_t typeSize) {
|
||||||
int i = 0;
|
int i = 0;
|
||||||
while(pointers != NULL) {
|
while(pointers != NULL) {
|
||||||
pointers++;
|
pointers += typeSize;
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
return i;
|
return i;
|
||||||
|
|||||||
+16
-1
@@ -8,9 +8,24 @@
|
|||||||
typedef enum FOModOrder { ASC, DESC, ORD } FOModOrder_t;
|
typedef enum FOModOrder { ASC, DESC, ORD } FOModOrder_t;
|
||||||
|
|
||||||
bool validateNode(xmlNodePtr * node, bool skipText, const char * names, ...);
|
bool validateNode(xmlNodePtr * node, bool skipText, const char * names, ...);
|
||||||
|
/**
|
||||||
|
* @brief Free memory of and xmlChar and return a strdup version. just to make sure there is nothing remaining in libxml
|
||||||
|
*/
|
||||||
char * freeAndDup(xmlChar * line);
|
char * freeAndDup(xmlChar * line);
|
||||||
FOModOrder_t getFOModOrder(const char * order);
|
FOModOrder_t getFOModOrder(const char * order);
|
||||||
|
/**
|
||||||
|
* @brief replace / by \
|
||||||
|
* @param path
|
||||||
|
*/
|
||||||
void fixPath(char * path);
|
void fixPath(char * path);
|
||||||
int countUntilNull(void * pointers);
|
|
||||||
|
/**
|
||||||
|
* @brief Count the number of step before null
|
||||||
|
*
|
||||||
|
* @param pointers pointer to the list
|
||||||
|
* @param typeSize size of each element of the list
|
||||||
|
* @return size
|
||||||
|
*/
|
||||||
|
int countUntilNull(void * pointers, size_t typeSize);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1 +1,8 @@
|
|||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the user home dir regardless if he used sudo.
|
||||||
|
*
|
||||||
|
* @return char* path to the home dir
|
||||||
|
*/
|
||||||
char * getHome();
|
char * getHome();
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
#ifndef __INSTALL_H__
|
#ifndef __INSTALL_H__
|
||||||
#define __INSTALL_H__
|
#define __INSTALL_H__
|
||||||
|
#include <stdlib.h>
|
||||||
#define INSTALLED_FLAG_FILE "__DO_NOT_REMOVE__"
|
#define INSTALLED_FLAG_FILE "__DO_NOT_REMOVE__"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Add a mod to the folder defined in main.h
|
||||||
|
*
|
||||||
|
* @param filePath path to the mod file
|
||||||
|
* @param appId game for which the mod is destined to be used with.
|
||||||
|
* @return EXIT_SUCCESS or EXIT_FAILURE
|
||||||
|
*/
|
||||||
int addMod(char * filePath, int appId);
|
int addMod(char * filePath, int appId);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
#ifndef __MACRO_H__
|
#ifndef __MACRO_H__
|
||||||
#define __MACRO_H__
|
#define __MACRO_H__
|
||||||
|
|
||||||
//cannot be empty it's made for fixed size array
|
//cannot be empty it's made for fixed size array like the ones in steam.h
|
||||||
#define LEN(array) sizeof(array) / sizeof(array[0])
|
#define LEN(array) sizeof(array) / sizeof(array[0])
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+31
-16
@@ -64,15 +64,12 @@ int usage() {
|
|||||||
printf("Use --deploy or -d <APPID> to deploy the mods for the game\n");
|
printf("Use --deploy or -d <APPID> to deploy the mods for the game\n");
|
||||||
printf("Use --unbind <APPID> to rollback a deployment\n");
|
printf("Use --unbind <APPID> to rollback a deployment\n");
|
||||||
printf("Use --fomod <APPID> <MODID> to create a new mod using the result from the FOMod\n");
|
printf("Use --fomod <APPID> <MODID> to create a new mod using the result from the FOMod\n");
|
||||||
//TODO: as bonus
|
|
||||||
//printf("Use --start-game <APPID> to deploy the mods and launch the game through steam\n");
|
|
||||||
//printf("Use --steam in team cmdline options to deploy directly on game startup\n");
|
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
int validateAppId(const char * appIdStr) {
|
int validateAppId(const char * appIdStr) {
|
||||||
//strtoul set EINVAL(after C99) if the string is invalid
|
//strtoul set EINVAL(after C99) if the string is invalid
|
||||||
u_int32_t appid = strtoul(appIdStr, NULL, 10);
|
unsigned long appid = strtoul(appIdStr, NULL, 10);
|
||||||
if(errno == EINVAL) {
|
if(errno == EINVAL) {
|
||||||
printf("Appid has to be a valid number\n");
|
printf("Appid has to be a valid number\n");
|
||||||
return -1;
|
return -1;
|
||||||
@@ -89,7 +86,8 @@ int validateAppId(const char * appIdStr) {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
return appid;
|
//no valid appid goes far enough to justify long
|
||||||
|
return (int)appid;
|
||||||
}
|
}
|
||||||
|
|
||||||
int listGames(int argc, char ** argv) {
|
int listGames(int argc, char ** argv) {
|
||||||
@@ -100,7 +98,7 @@ int listGames(int argc, char ** argv) {
|
|||||||
printf("No game found\n");
|
printf("No game found\n");
|
||||||
} else {
|
} else {
|
||||||
while(gamesIds != NULL) {
|
while(gamesIds != NULL) {
|
||||||
int * gameIndex = (int*)gamesIds->data;
|
const int * gameIndex = (int*)gamesIds->data;
|
||||||
printf("%d: %s\n", GAMES_APPIDS[*gameIndex], GAMES_NAMES[*gameIndex]);
|
printf("%d: %s\n", GAMES_APPIDS[*gameIndex], GAMES_NAMES[*gameIndex]);
|
||||||
gamesIds = g_list_next(gamesIds);
|
gamesIds = g_list_next(gamesIds);
|
||||||
}
|
}
|
||||||
@@ -111,9 +109,9 @@ int listGames(int argc, char ** argv) {
|
|||||||
|
|
||||||
int add(int argc, char ** argv) {
|
int add(int argc, char ** argv) {
|
||||||
if(argc != 4) return usage();
|
if(argc != 4) return usage();
|
||||||
char * appIdStr = argv[2];
|
const char * appIdStr = argv[2];
|
||||||
|
|
||||||
u_int32_t appid = validateAppId(appIdStr);
|
int appid = validateAppId(appIdStr);
|
||||||
if(appid < 0) {
|
if(appid < 0) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
@@ -168,7 +166,7 @@ int listAllMods(int argc, char ** argv) {
|
|||||||
int installAndUninstallMod(int argc, char ** argv, bool install) {
|
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];
|
||||||
u_int32_t appid = validateAppId(appIdStr);
|
int appid = validateAppId(appIdStr);
|
||||||
if(appid < 0) {
|
if(appid < 0) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
@@ -176,7 +174,7 @@ int installAndUninstallMod(int argc, char ** argv, bool install) {
|
|||||||
int returnValue = EXIT_SUCCESS;
|
int returnValue = EXIT_SUCCESS;
|
||||||
|
|
||||||
//strtoul set EINVAL if the string is invalid
|
//strtoul set EINVAL if the string is invalid
|
||||||
u_int32_t modId = strtoul(argv[3], NULL, 10);
|
unsigned long modId = strtoul(argv[3], NULL, 10);
|
||||||
if(errno == EINVAL) {
|
if(errno == EINVAL) {
|
||||||
printf("ModId has to be a valid number\n");
|
printf("ModId has to be a valid number\n");
|
||||||
return -1;
|
return -1;
|
||||||
@@ -185,6 +183,7 @@ 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, MANAGER_FILES, MOD_FOLDER_NAME, appIdStr, NULL);
|
char * modFolder = g_build_filename(home, MANAGER_FILES, MOD_FOLDER_NAME, appIdStr, NULL);
|
||||||
|
free(home);
|
||||||
GList * mods = listFilesInFolder(modFolder);
|
GList * mods = listFilesInFolder(modFolder);
|
||||||
GList * modsFirstPointer = mods;
|
GList * modsFirstPointer = mods;
|
||||||
|
|
||||||
@@ -208,9 +207,14 @@ int installAndUninstallMod(int argc, char ** argv, bool install) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Create activated file
|
//Create activated file
|
||||||
FILE * fd = fopen(modFlag, "w");
|
FILE * fd = fopen(modFlag, "w+");
|
||||||
fwrite("", 1, 1, fd);
|
if(fd != NULL) {
|
||||||
fclose(fd);
|
fwrite("", 1, 1, fd);
|
||||||
|
fclose(fd);
|
||||||
|
} else {
|
||||||
|
printf("Could not interact with the activation file\n");
|
||||||
|
returnValue = EXIT_FAILURE;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
if(access(modFlag, F_OK) != 0) {
|
if(access(modFlag, F_OK) != 0) {
|
||||||
printf("The mod is not activated \n");
|
printf("The mod is not activated \n");
|
||||||
@@ -287,6 +291,8 @@ int deploy(int argc, char ** argv) {
|
|||||||
free(modFlag);
|
free(modFlag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_free(modFolder);
|
||||||
|
|
||||||
//const char * data = "lowerdir=gameFolder,gameFolder2,gameFolder3..."
|
//const char * data = "lowerdir=gameFolder,gameFolder2,gameFolder3..."
|
||||||
modsToInstall[modCount] = gameFolder;
|
modsToInstall[modCount] = gameFolder;
|
||||||
modsToInstall[modCount + 1] = NULL;
|
modsToInstall[modCount + 1] = NULL;
|
||||||
@@ -297,6 +303,7 @@ int deploy(int argc, char ** argv) {
|
|||||||
|
|
||||||
char * gameUpperDir = g_build_filename(home, MANAGER_FILES, 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, MANAGER_FILES, GAME_WORK_DIR_NAME, appIdStr, NULL);
|
char * gameWorkDir = g_build_filename(home, MANAGER_FILES, GAME_WORK_DIR_NAME, appIdStr, NULL);
|
||||||
|
free(home);
|
||||||
|
|
||||||
//unmount the game folder
|
//unmount the game folder
|
||||||
//DETACH + FORCE allow us to be sure it will be unload.
|
//DETACH + FORCE allow us to be sure it will be unload.
|
||||||
@@ -317,12 +324,16 @@ int deploy(int argc, char ** argv) {
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
g_free(steamGameFolder);
|
||||||
|
g_free(gameUpperDir);
|
||||||
|
g_free(gameWorkDir);
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int setup(int argc, char ** argv) {
|
int setup(int argc, char ** argv) {
|
||||||
if(argc != 3 ) return usage();
|
if(argc != 3 ) return usage();
|
||||||
char * appIdStr = argv[2];
|
const char * appIdStr = argv[2];
|
||||||
int appid = validateAppId(appIdStr);
|
int appid = validateAppId(appIdStr);
|
||||||
if(appid < 0) {
|
if(appid < 0) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
@@ -372,7 +383,7 @@ int setup(int argc, char ** argv) {
|
|||||||
|
|
||||||
int unbind(int argc, char ** argv) {
|
int unbind(int argc, char ** argv) {
|
||||||
if(argc != 3 ) return usage();
|
if(argc != 3 ) return usage();
|
||||||
char * appIdStr = argv[2];
|
const char * appIdStr = argv[2];
|
||||||
int appid = validateAppId(appIdStr);
|
int appid = validateAppId(appIdStr);
|
||||||
if(appid < 0) {
|
if(appid < 0) {
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
@@ -389,7 +400,7 @@ int unbind(int argc, char ** argv) {
|
|||||||
|
|
||||||
int removeMod(int argc, char ** argv) {
|
int removeMod(int argc, char ** argv) {
|
||||||
if(argc != 4) return usage();
|
if(argc != 4) return usage();
|
||||||
char * appIdStr = argv[2];
|
const char * appIdStr = argv[2];
|
||||||
int appid = validateAppId(appIdStr);
|
int appid = validateAppId(appIdStr);
|
||||||
if(appid < 0) {
|
if(appid < 0) {
|
||||||
printf("Invalid appid");
|
printf("Invalid appid");
|
||||||
@@ -424,6 +435,7 @@ int removeMod(int argc, char ** argv) {
|
|||||||
delete(filename, true);
|
delete(filename, true);
|
||||||
|
|
||||||
g_free(filename);
|
g_free(filename);
|
||||||
|
g_free(modFolder);
|
||||||
g_list_free_full(modsFirstPointer, free);
|
g_list_free_full(modsFirstPointer, free);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
@@ -473,6 +485,9 @@ int fomod(int argc, char ** argv) {
|
|||||||
|
|
||||||
free(destination);
|
free(destination);
|
||||||
g_list_free_full(modsFirstPointer, free);
|
g_list_free_full(modsFirstPointer, free);
|
||||||
|
g_free(modDestination);
|
||||||
|
g_free(modPath);
|
||||||
|
g_free(modFolder);
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,9 @@
|
|||||||
// in c "A" "B" is the same as "AB"
|
// in c "A" "B" is the same as "AB"
|
||||||
#define MANAGER_FILES ".local/share/" APP_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
|
||||||
#define GAME_FOLDER_NAME "GAME_FOLDER"
|
#define GAME_FOLDER_NAME "GAME_FOLDER"
|
||||||
|
//the director that will contain all modifications to game files while being deployed
|
||||||
#define GAME_UPPER_DIR_NAME "UPPER_DIRS"
|
#define GAME_UPPER_DIR_NAME "UPPER_DIRS"
|
||||||
|
//overlayfs temporary dir.
|
||||||
#define GAME_WORK_DIR_NAME "WORK_DIRS"
|
#define GAME_WORK_DIR_NAME "WORK_DIRS"
|
||||||
|
|||||||
@@ -96,6 +96,5 @@ void swapPlace(int appid, int modId, int modId2) {
|
|||||||
GList * list = listMods(appid);
|
GList * list = listMods(appid);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
g_list_free(list);
|
g_list_free(list);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,15 @@
|
|||||||
* @return GList of char containing the name of the mod folder in order
|
* @return GList of char containing the name of the mod folder in order
|
||||||
*/
|
*/
|
||||||
GList * listMods(int appid);
|
GList * listMods(int appid);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Change the mod order by swaping two mod
|
||||||
|
*
|
||||||
|
* @param appid the game
|
||||||
|
* index of the mod in the mod list.
|
||||||
|
* @param modId
|
||||||
|
* @param modId2
|
||||||
|
*/
|
||||||
void swapPlace(int appid, int modId, int modId2);
|
void swapPlace(int appid, int modId, int modId2);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,6 +1,15 @@
|
|||||||
#ifndef __OVERLAY_H__
|
#ifndef __OVERLAY_H__
|
||||||
#define __OVERLAY_H__
|
#define __OVERLAY_H__
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Overlayfs is what make it possible to deploy to the game files without altering anything.
|
||||||
|
* it allows us to overlay multiple folder over the game files. like appling filters to an image.
|
||||||
|
* @param sources a null ended table of folder that will overlay of the game files
|
||||||
|
* @param dest the overlayed folder(the game data folder)
|
||||||
|
* @param upperdir the director that will store the changed files
|
||||||
|
* @param workdir a directory that will contains only temporary files.
|
||||||
|
* @return int error code
|
||||||
|
*/
|
||||||
int overlayMount(char ** sources, const char * dest, const char * upperdir, const char * workdir);
|
int overlayMount(char ** sources, const char * dest, const char * upperdir, const char * workdir);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+2
-2
@@ -223,9 +223,9 @@ GHashTable* search_games(int * status) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int getGameIdFromAppId(u_int32_t id) {
|
int getGameIdFromAppId(u_int32_t appid) {
|
||||||
for(int k = 0; k < LEN(GAMES_APPIDS); k++) {
|
for(int k = 0; k < LEN(GAMES_APPIDS); k++) {
|
||||||
if(id == GAMES_APPIDS[k]) {
|
if(appid == GAMES_APPIDS[k]) {
|
||||||
return k;
|
return k;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+19
-1
@@ -36,14 +36,32 @@ const static char * steamLibraries[] = {
|
|||||||
// order has to be the same as in GAMES_NAMES
|
// order has to be the same as in GAMES_NAMES
|
||||||
const static u_int32_t GAMES_APPIDS[] = {
|
const static u_int32_t GAMES_APPIDS[] = {
|
||||||
489830,
|
489830,
|
||||||
|
22330,
|
||||||
|
377160
|
||||||
};
|
};
|
||||||
|
|
||||||
//the name of the game in the steamapps/common folder
|
//the name of the game in the steamapps/common folder
|
||||||
const static char * GAMES_NAMES[] = {
|
const static char * GAMES_NAMES[] = {
|
||||||
"Skyrim Special Edition",
|
"Skyrim Special Edition",
|
||||||
|
"Oblivion",
|
||||||
|
"Fallout 4"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief list all installed games and the paths to the game's files
|
||||||
|
*
|
||||||
|
* @param status pointer to a status variable that will be modified to EXIT_SUCCESS or EXIT_FAILURE
|
||||||
|
* @return GHashTable* a map appid(int) => path(char *)
|
||||||
|
*/
|
||||||
|
//TODO: flip the return value and parameter
|
||||||
GHashTable* search_games(int * status);
|
GHashTable* search_games(int * status);
|
||||||
int getGameIdFromAppId(u_int32_t id);
|
|
||||||
|
/**
|
||||||
|
* @brief search the index of the game inside GAMES_NAMES or GAMES_APPIDS
|
||||||
|
*
|
||||||
|
* @param appid
|
||||||
|
* @return -1 in case of failure or the index of the game.
|
||||||
|
*/
|
||||||
|
int getGameIdFromAppId(u_int32_t appid);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user