mirror of
https://github.com/Polprzewodnikowy/N64FlashcartMenu.git
synced 2024-12-24 17:21:51 +01:00
Add toml library
This commit is contained in:
parent
7559850c49
commit
ffb6b3fd53
1
.github/workflows/build.yml
vendored
1
.github/workflows/build.yml
vendored
@ -32,6 +32,7 @@ jobs:
|
||||
- name: Build libdragon
|
||||
run: |
|
||||
cd ./libdragon
|
||||
# FIXME: this currently also builds the examples which adds to the build time.
|
||||
./build.sh # release --force-clean
|
||||
|
||||
- name: Build rom
|
||||
|
1
Makefile
1
Makefile
@ -16,6 +16,7 @@ SRCS = \
|
||||
flashcart/sc64/sc64.c \
|
||||
menu/menu.c \
|
||||
utils/fs.c \
|
||||
libs/toml/toml.c \
|
||||
main.c
|
||||
|
||||
OBJS = $(addprefix $(BUILD_DIR)/, $(addsuffix .o,$(basename $(SRCS))))
|
||||
|
13
README.md
13
README.md
@ -13,15 +13,16 @@
|
||||
Download the `sc64menu.n64` ROM from the latest action run assets.
|
||||
Add it to the root folder on your SD card.
|
||||
|
||||
Add a folder called `n64` in the root of your SD card.
|
||||
Create a file called `config.txt` in the `n64` folder.
|
||||
|
||||
Create a file called `config.sc64.toml.txt`
|
||||
Add the following content, replacing the comments.
|
||||
```
|
||||
game_path=<!-- path to your ROM from the root of your SD card -->
|
||||
save_path=<!-- path to a save file from the root of your SD card -->
|
||||
save_type=<!-- a number representing the save type (see save types) -->
|
||||
[last_rom]
|
||||
rom_path = "<!-- path to your ROM from the root of your SD card, note the quotes -->"
|
||||
save_path = "<!-- path to a save file from the root of your SD card, note the quotes -->"
|
||||
save_type = <!-- a number representing the save type (see save types) -->
|
||||
auto_load = <!-- a boolean value of `true` or `false` -->
|
||||
```
|
||||
Save it to the root folder on your SD card.
|
||||
|
||||
#### Save types
|
||||
`0` = NONE
|
||||
|
13
src/libs/toml/README.md
Normal file
13
src/libs/toml/README.md
Normal file
@ -0,0 +1,13 @@
|
||||
# Source
|
||||
https://github.com/cktan/tomlc99
|
||||
|
||||
# License
|
||||
MIT
|
||||
|
||||
# Description
|
||||
Used for generating and reading config files in an easy to use format.
|
||||
It currently targets version 1 of the spec and the lib might need updating from time to time.
|
||||
|
||||
# Notes
|
||||
It might be preferable to change to a submodule.
|
||||
There is currently an error related to -Werror=char-subscripts, possible solutions are in https://stackoverflow.com/questions/9972359/warning-array-subscript-has-type-char but for the moment all instances of `isdigit` have been adjusted to have `(unsigned char)` in the first parameter.
|
2380
src/libs/toml/toml.c
Normal file
2380
src/libs/toml/toml.c
Normal file
File diff suppressed because it is too large
Load Diff
175
src/libs/toml/toml.h
Normal file
175
src/libs/toml/toml.h
Normal file
@ -0,0 +1,175 @@
|
||||
/*
|
||||
MIT License
|
||||
|
||||
Copyright (c) CK Tan
|
||||
https://github.com/cktan/tomlc99
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
#ifndef TOML_H
|
||||
#define TOML_H
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable: 4996)
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
#define TOML_EXTERN extern "C"
|
||||
#else
|
||||
#define TOML_EXTERN extern
|
||||
#endif
|
||||
|
||||
typedef struct toml_timestamp_t toml_timestamp_t;
|
||||
typedef struct toml_table_t toml_table_t;
|
||||
typedef struct toml_array_t toml_array_t;
|
||||
typedef struct toml_datum_t toml_datum_t;
|
||||
|
||||
/* Parse a file. Return a table on success, or 0 otherwise.
|
||||
* Caller must toml_free(the-return-value) after use.
|
||||
*/
|
||||
TOML_EXTERN toml_table_t *toml_parse_file(FILE *fp, char *errbuf, int errbufsz);
|
||||
|
||||
/* Parse a string containing the full config.
|
||||
* Return a table on success, or 0 otherwise.
|
||||
* Caller must toml_free(the-return-value) after use.
|
||||
*/
|
||||
TOML_EXTERN toml_table_t *toml_parse(char *conf, /* NUL terminated, please. */
|
||||
char *errbuf, int errbufsz);
|
||||
|
||||
/* Free the table returned by toml_parse() or toml_parse_file(). Once
|
||||
* this function is called, any handles accessed through this tab
|
||||
* directly or indirectly are no longer valid.
|
||||
*/
|
||||
TOML_EXTERN void toml_free(toml_table_t *tab);
|
||||
|
||||
/* Timestamp types. The year, month, day, hour, minute, second, z
|
||||
* fields may be NULL if they are not relevant. e.g. In a DATE
|
||||
* type, the hour, minute, second and z fields will be NULLs.
|
||||
*/
|
||||
struct toml_timestamp_t {
|
||||
struct { /* internal. do not use. */
|
||||
int year, month, day;
|
||||
int hour, minute, second, millisec;
|
||||
char z[10];
|
||||
} __buffer;
|
||||
int *year, *month, *day;
|
||||
int *hour, *minute, *second, *millisec;
|
||||
char *z;
|
||||
};
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
* Enhanced access methods
|
||||
*/
|
||||
struct toml_datum_t {
|
||||
int ok;
|
||||
union {
|
||||
toml_timestamp_t *ts; /* ts must be freed after use */
|
||||
char *s; /* string value. s must be freed after use */
|
||||
int b; /* bool value */
|
||||
int64_t i; /* int value */
|
||||
double d; /* double value */
|
||||
} u;
|
||||
};
|
||||
|
||||
/* on arrays: */
|
||||
/* ... retrieve size of array. */
|
||||
TOML_EXTERN int toml_array_nelem(const toml_array_t *arr);
|
||||
/* ... retrieve values using index. */
|
||||
TOML_EXTERN toml_datum_t toml_string_at(const toml_array_t *arr, int idx);
|
||||
TOML_EXTERN toml_datum_t toml_bool_at(const toml_array_t *arr, int idx);
|
||||
TOML_EXTERN toml_datum_t toml_int_at(const toml_array_t *arr, int idx);
|
||||
TOML_EXTERN toml_datum_t toml_double_at(const toml_array_t *arr, int idx);
|
||||
TOML_EXTERN toml_datum_t toml_timestamp_at(const toml_array_t *arr, int idx);
|
||||
/* ... retrieve array or table using index. */
|
||||
TOML_EXTERN toml_array_t *toml_array_at(const toml_array_t *arr, int idx);
|
||||
TOML_EXTERN toml_table_t *toml_table_at(const toml_array_t *arr, int idx);
|
||||
|
||||
/* on tables: */
|
||||
/* ... retrieve the key in table at keyidx. Return 0 if out of range. */
|
||||
TOML_EXTERN const char *toml_key_in(const toml_table_t *tab, int keyidx);
|
||||
/* ... returns 1 if key exists in tab, 0 otherwise */
|
||||
TOML_EXTERN int toml_key_exists(const toml_table_t *tab, const char *key);
|
||||
/* ... retrieve values using key. */
|
||||
TOML_EXTERN toml_datum_t toml_string_in(const toml_table_t *arr,
|
||||
const char *key);
|
||||
TOML_EXTERN toml_datum_t toml_bool_in(const toml_table_t *arr, const char *key);
|
||||
TOML_EXTERN toml_datum_t toml_int_in(const toml_table_t *arr, const char *key);
|
||||
TOML_EXTERN toml_datum_t toml_double_in(const toml_table_t *arr,
|
||||
const char *key);
|
||||
TOML_EXTERN toml_datum_t toml_timestamp_in(const toml_table_t *arr,
|
||||
const char *key);
|
||||
/* .. retrieve array or table using key. */
|
||||
TOML_EXTERN toml_array_t *toml_array_in(const toml_table_t *tab,
|
||||
const char *key);
|
||||
TOML_EXTERN toml_table_t *toml_table_in(const toml_table_t *tab,
|
||||
const char *key);
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
* lesser used
|
||||
*/
|
||||
/* Return the array kind: 't'able, 'a'rray, 'v'alue, 'm'ixed */
|
||||
TOML_EXTERN char toml_array_kind(const toml_array_t *arr);
|
||||
|
||||
/* For array kind 'v'alue, return the type of values
|
||||
i:int, d:double, b:bool, s:string, t:time, D:date, T:timestamp, 'm'ixed
|
||||
0 if unknown
|
||||
*/
|
||||
TOML_EXTERN char toml_array_type(const toml_array_t *arr);
|
||||
|
||||
/* Return the key of an array */
|
||||
TOML_EXTERN const char *toml_array_key(const toml_array_t *arr);
|
||||
|
||||
/* Return the number of key-values in a table */
|
||||
TOML_EXTERN int toml_table_nkval(const toml_table_t *tab);
|
||||
|
||||
/* Return the number of arrays in a table */
|
||||
TOML_EXTERN int toml_table_narr(const toml_table_t *tab);
|
||||
|
||||
/* Return the number of sub-tables in a table */
|
||||
TOML_EXTERN int toml_table_ntab(const toml_table_t *tab);
|
||||
|
||||
/* Return the key of a table*/
|
||||
TOML_EXTERN const char *toml_table_key(const toml_table_t *tab);
|
||||
|
||||
/*--------------------------------------------------------------
|
||||
* misc
|
||||
*/
|
||||
TOML_EXTERN int toml_utf8_to_ucs(const char *orig, int len, int64_t *ret);
|
||||
TOML_EXTERN int toml_ucs_to_utf8(int64_t code, char buf[6]);
|
||||
TOML_EXTERN void toml_set_memutil(void *(*xxmalloc)(size_t),
|
||||
void (*xxfree)(void *));
|
||||
|
||||
/*--------------------------------------------------------------
|
||||
* deprecated
|
||||
*/
|
||||
/* A raw value, must be processed by toml_rto* before using. */
|
||||
typedef const char *toml_raw_t;
|
||||
TOML_EXTERN toml_raw_t toml_raw_in(const toml_table_t *tab, const char *key);
|
||||
TOML_EXTERN toml_raw_t toml_raw_at(const toml_array_t *arr, int idx);
|
||||
TOML_EXTERN int toml_rtos(toml_raw_t s, char **ret);
|
||||
TOML_EXTERN int toml_rtob(toml_raw_t s, int *ret);
|
||||
TOML_EXTERN int toml_rtoi(toml_raw_t s, int64_t *ret);
|
||||
TOML_EXTERN int toml_rtod(toml_raw_t s, double *ret);
|
||||
TOML_EXTERN int toml_rtod_ex(toml_raw_t s, double *ret, char *buf, int buflen);
|
||||
TOML_EXTERN int toml_rtots(toml_raw_t s, toml_timestamp_t *ret);
|
||||
|
||||
#endif /* TOML_H */
|
131
src/menu/menu.c
131
src/menu/menu.c
@ -1,57 +1,103 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <fatfs/ff.h>
|
||||
#include <libdragon.h>
|
||||
|
||||
#include "flashcart/flashcart.h"
|
||||
#include "libs/toml/toml.h"
|
||||
|
||||
#include "menu.h"
|
||||
|
||||
|
||||
static char *config_path = "n64/config.txt";
|
||||
static char game_path[256];
|
||||
static char save_path[256];
|
||||
#define SC64_CONFIG_FILEPATH "sd://config.sc64.toml.txt"
|
||||
static toml_datum_t rom_path;
|
||||
static toml_datum_t save_path;
|
||||
static flashcart_save_type_t save_type = FLASHCART_SAVE_TYPE_NONE;
|
||||
static bool save_writeback = false;
|
||||
static bool auto_load_last_rom = false;
|
||||
|
||||
|
||||
static void get_string (char *buffer, size_t size, FIL *fil) {
|
||||
UINT br;
|
||||
char c;
|
||||
|
||||
for (size_t i = 0; i < size; i++) {
|
||||
assertf(f_read(fil, &c, 1, &br) == FR_OK, "Couldn't read string");
|
||||
if (br == 0 || c == '\r' || c == '\n') {
|
||||
*buffer = '\0';
|
||||
return;
|
||||
}
|
||||
*buffer++ = c;
|
||||
}
|
||||
}
|
||||
|
||||
static void load_config (void) {
|
||||
FIL fil;
|
||||
char buffer[266];
|
||||
FILE *fp = NULL;
|
||||
char error_buffer[266];
|
||||
|
||||
printf("Loading config file %s\n", SC64_CONFIG_FILEPATH);
|
||||
wait_ms(1000);
|
||||
|
||||
assertf(f_open(&fil, config_path, FA_READ) == FR_OK, "Couldn't open config file");
|
||||
fp = fopen(SC64_CONFIG_FILEPATH, "r");
|
||||
if (!fp) {
|
||||
printf("Error loading config file %s\n", SC64_CONFIG_FILEPATH);
|
||||
wait_ms(10000);
|
||||
assertf(!fp, "Couldn't open toml config file: %s", SC64_CONFIG_FILEPATH);
|
||||
|
||||
while (!f_eof(&fil)) {
|
||||
get_string(buffer, sizeof(buffer), &fil);
|
||||
if (strncmp("game_path=", buffer, 10) == 0) {
|
||||
strncpy(game_path, (buffer + 10), sizeof(game_path));
|
||||
} else if (strncmp("save_path=", buffer, 10) == 0) {
|
||||
strncpy(save_path, (buffer + 10), sizeof(save_path));
|
||||
save_writeback = true;
|
||||
} else if (strncmp("save_type=", buffer, 10) == 0) {
|
||||
save_type = (buffer[10] - '0');
|
||||
assertf(save_type < __FLASHCART_SAVE_TYPE_END, "Invalid save type in config file");
|
||||
}
|
||||
// TODO: generate a default config file.
|
||||
}
|
||||
|
||||
toml_table_t* conf = toml_parse_file(fp, error_buffer, sizeof(error_buffer));
|
||||
if (!conf) {
|
||||
printf("Error parsing config: %s\n", error_buffer);
|
||||
wait_ms(10000);
|
||||
//assertf(!conf, "Couldn't parse toml config: %s", error_buffer);
|
||||
}
|
||||
|
||||
fclose(fp);
|
||||
//assertf(!fclose(fp), "Couldn't close toml config file");
|
||||
fp = NULL;
|
||||
|
||||
toml_table_t* last_rom = toml_table_in(conf, "last_rom");
|
||||
if (!last_rom) {
|
||||
printf("Missing '[last_rom]' header in config\n");
|
||||
wait_ms(10000);
|
||||
//assertf(!last_rom, "Missing '[last_rom]' header in config");
|
||||
}
|
||||
|
||||
rom_path = toml_string_in(last_rom, "rom_path");
|
||||
if (!rom_path.ok) {
|
||||
printf("Couldn't read 'rom_path' value in config\n");
|
||||
wait_ms(10000);
|
||||
//assertf(!rom_path.ok, "Couldn't read 'rom_path' value in config\n");
|
||||
}
|
||||
else {
|
||||
printf("Found rom path: %s\n", rom_path.u.s );
|
||||
}
|
||||
|
||||
assertf(f_close(&fil) == FR_OK, "Couldn't close config file");
|
||||
}
|
||||
save_path = toml_string_in(last_rom, "save_path");
|
||||
if (!save_path.ok) {
|
||||
printf("Couldn't read 'save_path' value in config\n");
|
||||
wait_ms(10000);
|
||||
//assertf(!save_path.ok, "Couldn't read 'save_path' value in config");
|
||||
}
|
||||
else {
|
||||
printf("Found save path: %s\n", save_path.u.s );
|
||||
}
|
||||
|
||||
toml_datum_t tmp_save_type = toml_int_in(last_rom, "save_type");
|
||||
if (!tmp_save_type.ok) {
|
||||
printf("Couldn't read 'save_type' value in config\n");
|
||||
wait_ms(10000);
|
||||
//assertf(!tmp_save_type.ok, "Couldn't read 'save_type' int value in config");
|
||||
}
|
||||
else {
|
||||
printf("Found save type: %d\n", (int)tmp_save_type.u.i );
|
||||
}
|
||||
assertf((int)tmp_save_type.u.i < __FLASHCART_SAVE_TYPE_END, "Invalid save type in config file");
|
||||
save_type = (int)tmp_save_type.u.i;
|
||||
|
||||
toml_datum_t tmp_auto_load_last_rom = toml_bool_in(last_rom, "auto_load");
|
||||
if (!tmp_auto_load_last_rom.ok) {
|
||||
printf("Couldn't read 'auto_load' value in config\n");
|
||||
wait_ms(5000);
|
||||
}
|
||||
else {
|
||||
printf("Found autoload: %s\n", tmp_auto_load_last_rom.u.b ? "true" : "false");
|
||||
auto_load_last_rom = tmp_auto_load_last_rom.u.b;
|
||||
}
|
||||
|
||||
toml_free(conf);
|
||||
|
||||
}
|
||||
|
||||
void menu_restore (menu_t *menu) {
|
||||
// TODO: restore last menu state from SD card
|
||||
@ -65,14 +111,19 @@ void menu_run (menu_t *menu) {
|
||||
|
||||
load_config();
|
||||
|
||||
printf("N64 Flashcart Menu\n\n");
|
||||
if (auto_load_last_rom) { // TODO: check if there is a button input to cancel.
|
||||
|
||||
printf("Loading ROM: %s\n", game_path);
|
||||
assertf(flashcart_load_rom(game_path) == FLASHCART_OK, "ROM load error");
|
||||
|
||||
printf("Loading save: %s, type: %d, writeback: %d\n", save_path, save_type, save_writeback);
|
||||
assertf(flashcart_load_save(save_path, save_type, save_writeback) == FLASHCART_OK, "Save load error");
|
||||
printf("Loading last ROM: %s\n", rom_path.u.s);
|
||||
assertf(flashcart_load_rom(rom_path.u.s) == FLASHCART_OK, "ROM load error");
|
||||
|
||||
printf("Loading save: %s, type: %d, writeback: %d\n", save_path.u.s, save_type, save_writeback);
|
||||
assertf(flashcart_load_save(save_path.u.s, save_type, save_writeback) == FLASHCART_OK, "Save load error");
|
||||
}
|
||||
else {
|
||||
printf("N64 Flashcart Menu\n\n");
|
||||
wait_ms(2000);
|
||||
// TODO: wait for a key input
|
||||
}
|
||||
// TODO: write menu state to SD card
|
||||
|
||||
menu->boot_params.device_type = BOOT_DEVICE_TYPE_ROM;
|
||||
|
Loading…
Reference in New Issue
Block a user