From 8bdba8891071110fe3f04de81dbe375c9c1caa80 Mon Sep 17 00:00:00 2001 From: Jan200101 Date: Thu, 30 Jul 2020 01:57:26 +0200 Subject: Initial commit --- src/common.c | 21 +++++++++++++ src/common.h | 28 +++++++++++++++++ src/dxvk.c | 98 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/dxvk.h | 9 ++++++ src/main.c | 47 ++++++++++++++++++++++++++++ src/main.h | 7 +++++ src/net.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/net.h | 10 ++++++ src/wine.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/wine.h | 9 ++++++ 10 files changed, 426 insertions(+) create mode 100644 src/common.c create mode 100644 src/common.h create mode 100644 src/dxvk.c create mode 100644 src/dxvk.h create mode 100644 src/main.c create mode 100644 src/main.h create mode 100644 src/net.c create mode 100644 src/net.h create mode 100644 src/wine.c create mode 100644 src/wine.h (limited to 'src') diff --git a/src/common.c b/src/common.c new file mode 100644 index 0000000..f3131e0 --- /dev/null +++ b/src/common.c @@ -0,0 +1,21 @@ +#include +#include + +#include "common.h" + +void print_help(const struct Command* commands, const size_t size) +{ + int longestCommand = 0; + + for (size_t i = 0; i < size; ++i) + { + int commandLength = strlen(commands[i].name); + + if (commandLength > longestCommand) longestCommand = commandLength; + } + + for (size_t i = 0; i < size; ++i) + { + printf("\t%-*s\t%s\n", longestCommand, commands[i].name, commands[i].description); + } +} diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..8b9d95b --- /dev/null +++ b/src/common.h @@ -0,0 +1,28 @@ +#ifndef COMMON_H +#define COMMON_H + +#include +#include + +#define ARRAY_LEN(arr) sizeof(arr) / sizeof(arr[0]) + +#define WINE_API "https://lutris.net/api/runners/wine" +#define DXVK_API "https://api.github.com/repos/lutris/dxvk/releases" + +#define USER_AGENT NAME "/" VERSION + + +struct MemoryStruct { + uint8_t* memory; + size_t size; +}; + +struct Command { + char* name; + int (*func)(int, char**); + char* description; +}; + +void print_help(const struct Command*, size_t); + +#endif \ No newline at end of file diff --git a/src/dxvk.c b/src/dxvk.c new file mode 100644 index 0000000..32d7d69 --- /dev/null +++ b/src/dxvk.c @@ -0,0 +1,98 @@ +#include +#include +#include +#include + +#include "dxvk.h" +#include "net.h" +#include "common.h" + +const static struct Command dxvk_commands[] = { + { .name = "install", .func = dxvk_install, .description = "download and install a dxvk version" }, + { .name = "list", .func = dxvk_list, .description = "list available dxvk versions" }, + { .name = "help", .func = dxvk_help, .description = "shows this message" }, +}; + +int dxvk(int argc, char** argv) +{ + if (argc > 2) + { + for (int i = 0; i < ARRAY_LEN(dxvk_commands); ++i) + { + if (!strcmp(dxvk_commands[i].name, argv[2])) return dxvk_commands[i].func(argc, argv); + } + } + + return dxvk_help(argc, argv); +} + + +int dxvk_install(int argc, char** argv) +{ + if (argc == 4) + { + struct json_object* runner = fetchJSON(DXVK_API); + + if (runner) + { + + int choice = atoi(argv[3]); + + if (choice > json_object_array_length(runner) - 1 || choice < 0) + { + printf("`%i' is not a valid ID\n\nrun `polecat dxvk list' to get a valid ID", choice); + } + else + { + struct json_object* version = json_object_array_get_idx(runner, choice); + struct json_object* assets; + + json_object_object_get_ex(version, "assets", &assets); + version =json_object_array_get_idx(assets, 0); + + json_object_object_get_ex(version, "browser_download_url", &assets); + + char* name = basename((char*)json_object_get_string(assets)); + + printf("Downloading %s", json_object_get_string(assets)); + downloadFile(json_object_get_string(assets), name); + printf("\nDone\n"); + } + } + } + else + { + puts("Usage: polecat dxvk download \n\nIDs are obtained via `polecat dxvk list' "); + } + return 0; +} + +int dxvk_list(int argc, char** argv) +{ + struct json_object* runner = fetchJSON(DXVK_API); + + if (runner) + { + puts("Installable DXVK versions:"); + + for (size_t i = 0; i < json_object_array_length(runner); ++i) + { + struct json_object* version = json_object_array_get_idx(runner, i); + struct json_object* name; + + json_object_object_get_ex(version, "name", &name); + printf(" [%zu]\t%s\n", i, json_object_get_string(name)); + } + } + + return 0; +} + +int dxvk_help(int argc, char** argv) +{ + puts("usage: polecat dxvk \n\nList of commands:"); + + print_help(dxvk_commands, ARRAY_LEN(dxvk_commands)); + + return 0; +} \ No newline at end of file diff --git a/src/dxvk.h b/src/dxvk.h new file mode 100644 index 0000000..ef423e2 --- /dev/null +++ b/src/dxvk.h @@ -0,0 +1,9 @@ +#ifndef DXVK_H +#define DXVK_H + +int dxvk(int, char**); +int dxvk_install(int, char**); +int dxvk_list(int, char**); +int dxvk_help(int, char**); + +#endif \ No newline at end of file diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..2e7655d --- /dev/null +++ b/src/main.c @@ -0,0 +1,47 @@ +#include +#include + +#include "main.h" +#include "wine.h" +#include "dxvk.h" +#include "common.h" + +const static struct Command main_commands[] = { + { .name = "wine", .func = wine, .description = "manage wine versions" }, + { .name = "dxvk", .func = dxvk, .description = "manage dxvk versions" }, + { .name = "info", .func = main_info, .description = "show some information about polecat" }, + { .name = "help", .func = main_help, .description = "displays this message" }, +}; + + +int main(int argc, char** argv) +{ + if (argc > 1) + { + for (int i = 0; i < ARRAY_LEN(main_commands); ++i) + { + if (!strcmp(main_commands[i].name, argv[1])) return main_commands[i].func(argc, argv); + } + } + + return main_help(argc, argv); +} + +int main_info(int argc, char** argv) +{ + printf("Version:\t\t%s\n" + "User-Agent:\t\t%s/%s\n", + VERSION, + NAME, VERSION); + + return 0; +} + +int main_help(int argc, char** argv) +{ + puts("usage: polecat \n\nList of commands:"); + + print_help(main_commands, ARRAY_LEN(main_commands)); + + return 0; +} \ No newline at end of file diff --git a/src/main.h b/src/main.h new file mode 100644 index 0000000..594b29e --- /dev/null +++ b/src/main.h @@ -0,0 +1,7 @@ +#ifndef MAIN_H +#define MAIN_H + +extern int main_help(int, char**); +extern int main_info(int, char**); + +#endif \ No newline at end of file diff --git a/src/net.c b/src/net.c new file mode 100644 index 0000000..f7dc481 --- /dev/null +++ b/src/net.c @@ -0,0 +1,100 @@ +#include +#include +#include +#include +#include +#include + +#include "net.h" +#include "common.h" + +size_t memoryCallback(void* contents, size_t size, size_t nmemb, void* userp) +{ + size_t realsize = size * nmemb; + struct MemoryStruct* mem = (struct MemoryStruct*)userp; + + uint8_t* ptr = realloc(mem->memory, mem->size + realsize + 1); + if(ptr == NULL) { + /* out of memory! */ + puts("out of memory"); + return 0; + } + + mem->memory = ptr; + memcpy(&(mem->memory[mem->size]), contents, realsize); + mem->size += realsize; + mem->memory[mem->size] = 0; + + return realsize; +} + +struct MemoryStruct* downloadToRam(const char* URL) +{ + CURL* curl_handle; + CURLcode res; + + struct MemoryStruct* chunk = malloc(sizeof(struct MemoryStruct)); + + chunk->memory = malloc(1); + chunk->size = 0; + + curl_global_init(CURL_GLOBAL_ALL); + + curl_handle = curl_easy_init(); + + curl_easy_setopt(curl_handle, CURLOPT_URL, URL); + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, memoryCallback); + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void*)chunk); + curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, USER_AGENT); + curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1L); + + res = curl_easy_perform(curl_handle); + + long http_code = 0; + curl_easy_getinfo (curl_handle, CURLINFO_RESPONSE_CODE, &http_code); + + if(res != CURLE_OK) { + fprintf(stderr, "curl_easy_perform() failed: %s\n", + curl_easy_strerror(res)); + return NULL; + } + else if (http_code != 200) + { + fprintf(stderr, "Server didn't respond as expected [HTTP Error %li]\n", http_code); + return NULL; + } + + curl_easy_cleanup(curl_handle); + curl_global_cleanup(); + + return chunk; +} + +int downloadFile(const char* URL, const char* path) +{ + struct MemoryStruct* chunk = downloadToRam(URL); + + if (chunk) + { + FILE* file = fopen(path, "wb"); + fwrite(chunk->memory, chunk->size, 1, file); + fclose(file); + + free(chunk->memory); + free(chunk); + } + + return 0; +} + +struct json_object* fetchJSON(const char* URL) +{ + struct MemoryStruct* chunk = downloadToRam(URL); + + struct json_object* json = json_tokener_parse((char*)chunk->memory); + + free(chunk->memory); + free(chunk); + + return json; +} \ No newline at end of file diff --git a/src/net.h b/src/net.h new file mode 100644 index 0000000..2b203fa --- /dev/null +++ b/src/net.h @@ -0,0 +1,10 @@ +#ifndef NET_H +#define NET_H + +#include + +size_t WriteMemoryCallback(void*, size_t, size_t, void*); +int downloadFile(const char*, const char*); +struct json_object* fetchJSON(const char*); + +#endif \ No newline at end of file diff --git a/src/wine.c b/src/wine.c new file mode 100644 index 0000000..2c304ed --- /dev/null +++ b/src/wine.c @@ -0,0 +1,97 @@ +#include +#include +#include +#include + +#include "wine.h" +#include "net.h" +#include "common.h" + +const static struct Command wine_commands[] = { + { .name = "install", .func = wine_install, .description = "download and install a wine version from lutris" }, + { .name = "list", .func = wine_list, .description = "list available wine versions" }, + { .name = "help", .func = wine_help, .description = "shows this message" }, +}; + +int wine(int argc, char** argv) +{ + if (argc > 2) + { + for (int i = 0; i < ARRAY_LEN(wine_commands); ++i) + { + if (!strcmp(wine_commands[i].name, argv[2])) return wine_commands[i].func(argc, argv); + } + } + + return wine_help(argc, argv); +} + + +int wine_install(int argc, char** argv) +{ + if (argc == 4) + { + struct json_object* runner = fetchJSON(WINE_API); + + if (runner) + { + struct json_object* versions; + json_object_object_get_ex(runner, "versions", &versions); + + int choice = atoi(argv[3]); + + if (choice > json_object_array_length(versions) - 1 || choice < 0) + { + printf("`%i' is not a valid ID\n\nrun `polecat wine list' to get a valid ID", choice); + } + else + { + struct json_object* url; + struct json_object* value = json_object_array_get_idx(versions, choice); + + json_object_object_get_ex(value, "url", &url); + char* name = basename((char*)json_object_get_string(url)); + + printf("Downloading %s", name); + downloadFile(json_object_get_string(url), name); + printf("\nDone\n"); + } + } + } + else + { + puts("Usage: polecat wine download \n\nIDs are obtained via `polecat wine list' "); + } + return 0; +} + +int wine_list(int argc, char** argv) +{ + struct json_object* runner = fetchJSON(WINE_API); + + if (runner) + { + struct json_object* versions, *value, *val; + json_object_object_get_ex(runner, "versions", &versions); + + puts("Installable wine versions:"); + + for (size_t i = 0; i < json_object_array_length(versions); ++i) + { + value = json_object_array_get_idx(versions, i); + json_object_object_get_ex(value, "version", &val); + printf(" [%zu]\t%s\n", i, json_object_get_string(val)); + } + } + + return 0; +} + +int wine_help(int argc, char** argv) +{ + puts("usage: polecat wine \n\nList of commands:"); + + print_help(wine_commands, ARRAY_LEN(wine_commands)); + + return 0; +} \ No newline at end of file diff --git a/src/wine.h b/src/wine.h new file mode 100644 index 0000000..872a17e --- /dev/null +++ b/src/wine.h @@ -0,0 +1,9 @@ +#ifndef WINE_H +#define WINE_H + +int wine(int, char**); +int wine_install(int, char**); +int wine_list(int, char**); +int wine_help(int, char**); + +#endif \ No newline at end of file -- cgit v1.2.3