diff --git a/src/main.c b/src/main.c index c167e72..46591f0 100644 --- a/src/main.c +++ b/src/main.c @@ -1,6 +1,5 @@ #include #include -#include #include #include #include @@ -21,8 +20,6 @@ #define ENABLED_COLOR "\033[0;32m" #define DISABLED_COLOR "\033[0;31m" -GHashTable * gamePaths; - static bool isRoot() { return getuid() == 0; } @@ -65,7 +62,13 @@ static int usage() { return EXIT_FAILURE; } -static int validateAppId(const char * appIdStr) { +static error_t validateAppId(const char * appIdStr) { + GHashTable * gamePaths; + error_t status = search_games(&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); @@ -91,6 +94,13 @@ static int validateAppId(const char * appIdStr) { static int listGames(int argc, char **) { if(argc != 2) return usage(); + + GHashTable * gamePaths; + error_t status = search_games(&gamePaths); + if(status == ERR_FAILURE) { + return EXIT_FAILURE; + } + GList * gamesIds = g_hash_table_get_keys(gamePaths); GList * gamesIdsFirstPointer = gamesIds; if(g_list_length(gamesIds) == 0) { @@ -103,7 +113,7 @@ static int listGames(int argc, char **) { } } g_list_free(gamesIdsFirstPointer); - return EXIT_SUCCESS; + return EXIT_FAILURE; } static int add(int argc, char ** argv) { @@ -303,6 +313,15 @@ static int deploy(int argc, char ** argv) { modsToInstall[modCount + 1] = NULL; printf("Mounting the overlay\n"); int gameId = getGameIdFromAppId(appid); + + GHashTable * gamePaths; + error_t lookup_status = search_games(&gamePaths); + if(lookup_status == ERR_FAILURE) { + free(home); + return ERR_FAILURE; + } + + const char * path = g_hash_table_lookup(gamePaths, &gameId); char * steamGameFolder = g_build_path("/", path, "steamapps/common", GAMES_NAMES[gameId], "Data", NULL); @@ -353,6 +372,13 @@ static int setup(int argc, char ** argv) { free(gameUpperDir); free(gameWorkDir); + GHashTable * gamePaths; + error_t status = search_games(&gamePaths); + if(status == ERR_FAILURE) { + free(home); + return ERR_FAILURE; + } + const char * path = g_hash_table_lookup(gamePaths, &gameId); char * steamGameFolder = g_build_path("/", path, "steamapps/common", GAMES_NAMES[gameId], "Data", NULL); @@ -393,6 +419,12 @@ static int unbind(int argc, char ** argv) { if(appid < 0) { return EXIT_FAILURE; } + + GHashTable * gamePaths; + error_t status = search_games(&gamePaths); + if(status == ERR_FAILURE) + return EXIT_FAILURE; + int gameId = getGameIdFromAppId(appid); const char * path = g_hash_table_lookup(gamePaths, &gameId); char * steamGameFolder = g_build_path("/", path, "steamapps/common", GAMES_NAMES[gameId], "Data", NULL); @@ -531,17 +563,7 @@ int main(int argc, char ** argv) { return EXIT_FAILURE; } - int searchStatus; - gamePaths = search_games(&searchStatus); - - int returnValue = EXIT_SUCCESS; - if(searchStatus == EXIT_FAILURE) { - returnValue = EXIT_FAILURE; - fprintf(stderr, "Error while looking up libraries, do you have steam installed ?"); - goto exit; - } - char * home = getHome(); char * configFolder = g_build_filename(home, MANAGER_FILES, NULL); free(home); @@ -554,18 +576,17 @@ int main(int argc, char ** argv) { if(getuid() == 0) { fprintf(stderr, "For the first run please avoid sudo\n"); returnValue = EXIT_FAILURE; - goto exit2; + goto exit; } else { //leading 0 == octal int i = g_mkdir_with_parents(configFolder, 0755); if(i < 0) { fprintf(stderr, "Could not create configs, check access rights for this path: %s", configFolder); - goto exit2; + goto exit; } } } - if(strcmp(argv[1], "--list-games") == 0 || strcmp(argv[1], "-l") == 0) returnValue = listGames(argc, argv); @@ -613,9 +634,8 @@ int main(int argc, char ** argv) { returnValue = EXIT_FAILURE; } -exit2: - g_free(configFolder); - g_hash_table_destroy(gamePaths); exit: + g_free(configFolder); + freeGameTableSingleton(); return returnValue; } diff --git a/src/main.h b/src/main.h index 3aa9d13..a563bd6 100644 --- a/src/main.h +++ b/src/main.h @@ -1,9 +1,11 @@ #ifndef __MAIN_H__ #define __MAIN_H__ -//no function should ever be put here, only keep important macros here +#include -#define APP_NAME "modmanager" +//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 // in c "A" "B" is the same as "AB" #define MANAGER_FILES ".local/share/" APP_NAME diff --git a/src/steam.c b/src/steam.c index 177d934..87ae8d1 100644 --- a/src/steam.c +++ b/src/steam.c @@ -1,6 +1,7 @@ #include "steam.h" #include "macro.h" #include "getHome.h" +#include "main.h" #include #include #include @@ -190,11 +191,21 @@ static void freeLibraries(ValveLibraries_t * libraries, int size) { free(libraries); } -GHashTable* search_games(int * status) { +static GHashTable* gameTableSingleton = NULL; + +void freeGameTableSingleton() { + if(gameTableSingleton != NULL)g_hash_table_destroy(gameTableSingleton); +} + +error_t search_games(GHashTable ** p_hashTable) { + if(gameTableSingleton != NULL) { + *p_hashTable = gameTableSingleton; + return ERR_SUCCESS; + } + ValveLibraries_t * libraries = NULL; size_t size = 0; char * home = getHome(); - *status = EXIT_SUCCESS; for(unsigned long i = 0; i < LEN(steamLibraries); i++) { char * path = g_build_filename(home, steamLibraries[i], "steamapps/libraryfolders.vdf", NULL); @@ -212,8 +223,7 @@ GHashTable* search_games(int * status) { free(home); if(libraries == NULL) { - *status = EXIT_FAILURE; - return NULL; + return ERR_FAILURE; } GHashTable* table = g_hash_table_new_full(g_int_hash, g_int_equal, free, free); @@ -231,7 +241,9 @@ GHashTable* search_games(int * status) { } freeLibraries(libraries, size); - return table; + *p_hashTable = table; + gameTableSingleton = table; + return ERR_SUCCESS; } diff --git a/src/steam.h b/src/steam.h index 880fe18..92f3e13 100644 --- a/src/steam.h +++ b/src/steam.h @@ -45,12 +45,14 @@ _Static_assert(LEN(GAMES_APPIDS) == LEN(GAMES_NAMES), "Game APPIDS and Game Name /** * @brief list all installed games and the paths to the game's files + * This method has a singleton so after the first execution it will no rescan for new games. * * @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 *) + * @return GHashTable* a map appid(int) => path(char *) to the corresponding steam library */ - //TODO: flip the return value and parameter -GHashTable* search_games(int * status); +error_t search_games(GHashTable** tablePointer); + +void freeGameTableSingleton(void); /** * @brief search the index of the game inside GAMES_NAMES or GAMES_APPIDS