Browse Source

convert json to csv for local use and add usage message

Also contains initial boilerplate for instance creation.
master
Shokara 4 months ago
parent
commit
e76a13b3b8
Signed by: shokara GPG Key ID: 7F5702DEF8E6DC82
  1. 5
      README
  2. 45
      somc.c
  3. 173
      versions.c
  4. 1
      versions.h

5
README

@ -13,7 +13,8 @@ Minecraft versions tested:
Usage
-----
TODO
somc list-versions
somc instance-create name version-id
Dependencies
------------
@ -30,7 +31,7 @@ Compiling/Installing
--------------------
git clone https://gt.kalli.st/shokara/somc
cd somc
git submodule update --init --recursive # if cJSON isn't installed
git submodule update --init # if cJSON isn't installed
# edit config.mk if necessary
make
make install

45
somc.c

@ -2,16 +2,31 @@
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>
#include "versions.h"
#include "somc.h"
char somc_data_dir[256];
static void usage(char *name);
static void usage(char *name)
{
printf("Usage: %s list-versions\n"
" %s instance-create name version-id\n",
name, name);
}
int main(int argc, char **argv)
{
char *home_dir;
if (argc == 1) {
usage(argv[0]);
return EXIT_FAILURE;
}
if ((home_dir = getenv("HOME")) == NULL) {
fprintf(stderr, "$HOME is not set? Defaulting to current directory.\n");
home_dir = ".";
@ -22,8 +37,34 @@ int main(int argc, char **argv)
sizeof(somc_data_dir) - strlen(somc_data_dir) - 1);
somc_data_dir[sizeof(somc_data_dir) - 1] = '\0';
mkdir(somc_data_dir, 0755);
chdir(somc_data_dir);
if (strncmp(argv[1], "list-versions", 13) == 0) {
if (argc != 2) {
usage(argv[0]);
return EXIT_FAILURE;
}
list_versions();
if (list_versions() < 0) {
fprintf(stderr, "versions failed to list "
"(%s/versions_manifest.json possibly "
"corrupt)\n", somc_data_dir);
return EXIT_FAILURE;
}
} else if (strncmp(argv[1], "instance-create", 15) == 0) {
if (argc != 4) {
usage(argv[0]);
return EXIT_FAILURE;
}
if (instance_create(argv[2], argv[3]) < 0) {
fprintf(stderr, "instance %s with version %s failed to create",
argv[3], argv[4]);
}
} else {
usage(argv[0]);
return EXIT_FAILURE;
}
return 0;
return EXIT_SUCCESS;
}

173
versions.c

@ -1,86 +1,171 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cJSON/cJSON.h>
#include <sys/stat.h>
#include <unistd.h>
#include <cJSON/cJSON.h>
#include "somc.h"
#include "fetch.h"
#define VERSION_MANIFEST_URL "https://launchermeta.mojang.com/mc/game/version_manifest.json"
static int get_version_manifest(char *manifest_path, int overwrite);
static int get_version_manifest(char *manifest_path, int overwrite)
static char manifest_path[32];
static char version_json_path[64];
static int get_version_manifest(int overwrite);
static int get_version_json(char *version_id, int overwrite);
/*
* get_version_manifest() fetches version_manifest.json from VERSION_MANIFEST_URL
* via curl and then parses that json into a csv file.
* The csv file's lines are formatted as:
* id, type, url
*
* An example is:
* b1.7.3, old_beta, https://url.to.minecraft/b1.7.3.json
*/
static int get_versions_csv(int overwrite)
{
if (fetch_file(VERSION_MANIFEST_URL, manifest_path, overwrite) != 0) {
fprintf(stderr, "minecraft version manifest failed to download");
return -1;
}
return 0;
}
FILE *fp;
char path[32];
char *data;
size_t len;
int list_versions(void)
{
int status = 0;
cJSON *json, *versions_arr, *version_obj;
char manifest_path[300];
char *manifest_data;
FILE *manifest_fp;
size_t manifest_len;
strncpy(path, ".somc.version_manifest.json", sizeof(path));
cJSON *json, *versions_arr, *version_obj;
strncpy(manifest_path, "versions/", sizeof(manifest_path));
mkdir(manifest_path, 0755);
strncat(manifest_path, "versions.csv", sizeof(manifest_path) - strlen(manifest_path) - 1);
strncpy(manifest_path, somc_data_dir, sizeof(manifest_path));
strncat(manifest_path, "/version_manifest.json",
sizeof(manifest_path) - strlen(manifest_path) - 1);
manifest_path[sizeof(manifest_path) - 1] = '\0';
/* exit if the csv already exists and overwrite flag isn't 0 */
if (overwrite != 0 && (fp = fopen(manifest_path, "r")) != NULL) {
fseek(fp, 0, SEEK_END);
if (ftell(fp) > 0) {
fprintf(stderr, "%s already exists", manifest_path);
return 0;
}
if (get_version_manifest(manifest_path, 0) < 0)
fclose(fp);
}
if (fetch_file(VERSION_MANIFEST_URL, path, overwrite) != 0) {
fprintf(stderr, "minecraft version manifest failed to download");
return -1;
}
if ((manifest_fp = fopen(manifest_path, "r")) == NULL) {
if ((fp = fopen(path, "r")) == NULL) {
perror("fopen for version manifest failed");
return -2;
}
fseek(manifest_fp, 0, SEEK_END);
manifest_len = ftell(manifest_fp);
rewind(manifest_fp);
fseek(fp, 0, SEEK_END);
len = ftell(fp);
rewind(fp);
manifest_data = malloc(manifest_len);
if (manifest_data == NULL) {
perror("malloc for manifest_data failed");
if ((data = malloc(len)) == NULL) {
perror("malloc for data failed");
status = -3;
goto end;
fclose(fp);
return -3;
}
fread(manifest_data, 1, manifest_len, manifest_fp);
fread(data, 1, len, fp);
json = cJSON_ParseWithLength(manifest_data, manifest_len);
free(manifest_data);
fclose(fp);
unlink(path);
json = cJSON_ParseWithLength(data, len);
free(data);
if (json == NULL) {
const char *error = cJSON_GetErrorPtr();
if (error != NULL)
fprintf(stderr, "json error before: %s\n", error);
status = -4;
goto json_end;
cJSON_Delete(json);
return -4;
}
if ((fp = fopen(manifest_path, "w")) == NULL) {
perror("fopen for versions.csv failed");
return -2;
}
versions_arr = cJSON_GetObjectItemCaseSensitive(json, "versions");
cJSON_ArrayForEach(version_obj, versions_arr) {
cJSON *id, *type;
cJSON *id, *type, *url;
id = cJSON_GetObjectItemCaseSensitive(version_obj, "id");
type = cJSON_GetObjectItemCaseSensitive(version_obj, "type");
url = cJSON_GetObjectItemCaseSensitive(version_obj, "url");
printf("%s (%s)\n", id->valuestring, type->valuestring);
fprintf(fp, "%s,%s,%s\n", id->valuestring, type->valuestring,
url->valuestring);
}
json_end:
cJSON_Delete(json);
end:
fclose(manifest_fp);
return status;
fclose(fp);
return 0;
}
static int get_version_json(char *version_id, int overwrite)
{
char version_json_url[32];
strncpy(version_json_path, version_id, sizeof(version_json_path));
strncat(version_json_path, ".json", sizeof(version_json_path)
- strlen(version_json_path) - 1);
if (fetch_file(VERSION_MANIFEST_URL, manifest_path, overwrite) != 0) {
fprintf(stderr, "minecraft version manifest failed to download");
return -1;
}
return 0;
}
int list_versions(void)
{
FILE *fp;
char line[256];
if (get_versions_csv(0) < 0)
return -1;
if ((fp = fopen(manifest_path, "r")) == NULL) {
perror("fopen for versions.csv failed");
return -2;
}
while (fgets(line, sizeof(line), fp) != NULL) {
char *id, *type;
id = strtok(line, ",");
type = strtok(NULL, ",");
printf("%s (%s)\n", id, type);
}
return 0;
}
int instance_create(char *name, char *version_id)
{
char instances_dir[256];
FILE *manifest_fp;
char *manifest_data;
size_t manifest_len;
strncpy(instances_dir, "instances/", sizeof(instances_dir));
mkdir(instances_dir, 0755);
strncat(instances_dir, name, sizeof(instances_dir)
- strlen(instances_dir) - 1);
mkdir(instances_dir, 0755);
chdir(instances_dir);
return 0;
}

1
versions.h

@ -1 +1,2 @@
int list_versions(void);
int instance_create(char *name, char *version_id);