Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ font = custom_target(
gekkoboot = executable(
'gekkoboot',
'source/main.c',
'source/utils.c',
'source/filesystem.c',
'source/shortcut.c',
'source/cli_args.c',
'source/fatfs/ff.c',
'source/fatfs/ffsystem.c',
'source/fatfs/ffunicode.c',
Expand Down
78 changes: 78 additions & 0 deletions source/cli_args.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#include "cli_args.h"
#include <ogc/system.h>
#include <stdlib.h>
#include <string.h>

#define MAX_NUM_ARGV 1024

// 0 - Failure
// 1 - OK/Empty
int
parse_cli_args(struct __argv *argv, char *cli_option_str) {
kprintf("Parsing CLI args...\n");

argv->argc = 0;
argv->length = 0;
argv->commandLine = NULL;

char *cli = cli_option_str;
char *dol_argv[MAX_NUM_ARGV];
int dol_argc = 0;
int size = strlen(cli_option_str);

// Parse CLI file
// https://github.com/emukidid/swiss-gc/blob/a0fa06d81360ad6d173acd42e4dd5495e268de42/cube/swiss/source/swiss.c#L1236
// First argument is at the beginning of the file
if (cli[0] != '\r' && cli[0] != '\n') {
dol_argv[dol_argc] = cli;
dol_argc++;
}

// Search for the others after each newline
for (int i = 0; i < size; i++) {
if (cli[i] == '\r' || cli[i] == '\n') {
cli[i] = '\0';
} else if (cli[i - 1] == '\0') {
dol_argv[dol_argc] = cli + i;
dol_argc++;
if (dol_argc >= MAX_NUM_ARGV) {
kprintf("Reached max of %i args.\n", MAX_NUM_ARGV);
break;
}
}
}

kprintf("Found %i CLI args\n", dol_argc);

if (!dol_argc) {
return 0;
}

// https://github.com/emukidid/swiss-gc/blob/f5319aab248287c847cb9468325ebcf54c993fb1/cube/swiss/source/aram/sidestep.c#L350
argv->argc = dol_argc;
argv->length = 1;

for (int i = 0; i < dol_argc; i++) {
size_t arg_length = strlen(dol_argv[i]) + 1;
argv->length += arg_length;
}

kprintf("CLI argv size is %iB\n", argv->length);
argv->commandLine = (char *) malloc(argv->length);

if (!argv->commandLine) {
kprintf("Couldn't allocate memory for CLI argv\n");
argv->length = 0;
return 0;
}

unsigned int position = 0;
for (int i = 0; i < dol_argc; i++) {
size_t arg_length = strlen(dol_argv[i]) + 1;
memcpy(argv->commandLine + position, dol_argv[i], arg_length);
position += arg_length;
}
argv->commandLine[argv->length - 1] = '\0';

return 1;
}
8 changes: 8 additions & 0 deletions source/cli_args.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
#ifndef INC_CLI_ARGS_H
#define INC_CLI_ARGS_H
#include <gctypes.h>

int
parse_cli_args(struct __argv *argv, char *cli_option_str);

#endif
115 changes: 115 additions & 0 deletions source/filesystem.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#include "filesystem.h"
#include "fatfs/ff.h"
#include "ffshim.h"
#include <ogc/system.h>
#include <stdlib.h>

FATFS fs;
FS_RESULT
fs_mount(const DISC_INTERFACE *iface_) {
iface = iface_;
return f_mount(&fs, "", 1);
}

void
fs_unmount() {
f_unmount("");
iface->shutdown();
iface = NULL;
}

void
fs_get_volume_label(const char *path, char *label) {
FRESULT res = f_getlabel(path, label, NULL);
if (res != FR_OK) {
*label = '\0';
}
}

FS_RESULT
_fs_read_file(void **contents_, const char *path, int is_string) {
FIL file;
FRESULT result = f_open(&file, path, FA_READ);
if (result != FR_OK) {
kprintf("Failed to open file: %s\n", get_fs_result_message(result));
return result;
}

size_t size = f_size(&file);
if (size <= 0) {
kprintf("File is empty\n");
return FS_FILE_EMPTY;
}
kprintf("File size: %iB\n", size);

// Malloc an extra byte if we are reading as a string incase we need to add NUL character.
void *contents = malloc(size + (is_string ? 1 : 0));
if (!contents) {
kprintf("Couldn't allocate memory for file\n");
return FS_NOT_ENOUGH_MEMORY;
}

kprintf("Reading file...\n");
UINT _;
result = f_read(&file, contents, size, &_);
if (result != FR_OK) {
kprintf("Failed to read file: %s\n", get_fs_result_message(result));
return result;
}

f_close(&file);

// Ensure files read as strings end with NUL character.
if (is_string) {
// This is safe because we malloc an extra byte above if reading as string.
((char *) contents)[size] = '\0';
}

*contents_ = contents;
return FS_OK;
}

FS_RESULT
fs_read_file(void **contents, const char *path) {
return _fs_read_file(contents, path, false);
}
FS_RESULT
fs_read_file_string(const char **contents, const char *path) {
return _fs_read_file((void **) contents, path, true);
}

#define NUM_FS_RESULT_MSGS 22
const char *fs_result_msgs[NUM_FS_RESULT_MSGS] = {
/*FS_OK ( 0)*/ "Succeeded",
/*FS_DISK_ERR ( 1)*/ "A hard error occurred in the low level disk I/O layer",
/*FS_INT_ERR ( 2)*/ "Assertion failed",
/*FS_NOT_READY ( 3)*/ "Device not ready",
/*FS_NO_FILE ( 4)*/ "Could not find the file",
/*FS_NO_PATH ( 5)*/ "Could not find the path",
/*FS_INVALID_NAME ( 6)*/ "The path name format is invalid",
/*FS_DENIED ( 7)*/ "Access denied due to prohibited access or directory full",
/*FS_EXIST ( 8)*/ "Access denied due to prohibited access",
/*FS_INVALID_OBJECT ( 9)*/ "The file/directory object is invalid",
/*FS_WRITE_PROTECTED (10)*/ "The physical drive is write protected",
/*FS_INVALID_DRIVE (11)*/ "The logical drive number is invalid",
/*FS_NOT_ENABLED (12)*/ "The volume has no work area",
/*FS_NO_FILESYSTEM (13)*/ "There is no valid FAT volume",
/*FS_MKFS_ABORTED (14)*/ "The f_mkfs() aborted due to any problem",
/*FS_TIMEOUT (15)*/
"Could not get a grant to access the volume within defined period",
/*FS_LOCKED (16)*/
"The operation is rejected according to the file sharing policy",
/*FS_NOT_ENOUGH_CORE (17)*/ "LFN working buffer could not be allocated",
/*FS_TOO_MANY_OPEN_FILES (18)*/ "Number of open files > FF_FS_LOCK",
/*FS_INVALID_PARAMETER (19)*/ "Given parameter is invalid",
/*FS_FILE_EMPTY (20)*/ "File is empty",
/*FS_NOT_ENOUGH_MEMORY (21)*/ "Not enough memory",
};

const char *
get_fs_result_message(FS_RESULT result) {
if (result < 0 || result >= NUM_FS_RESULT_MSGS) {
return "Unknown";
}
return fs_result_msgs[result];
}
45 changes: 45 additions & 0 deletions source/filesystem.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
#ifndef INC_FILESYSTEM_H
#define INC_FILESYSTEM_H
#include <ogc/disc_io.h>

// See ./fatfs/ff.h:276
typedef enum {
FS_OK = 0, /* ( 0) Succeeded */
FS_DISK_ERR, /* ( 1) A hard error occurred in the low level disk I/O layer */
FS_INT_ERR, /* ( 2) Assertion failed */
FS_NOT_READY, /* ( 3) The physical drive cannot work */
FS_NO_FILE, /* ( 4) Could not find the file */
FS_NO_PATH, /* ( 5) Could not find the path */
FS_INVALID_NAME, /* ( 6) The path name format is invalid */
FS_DENIED, /* ( 7) Access denied due to prohibited access or directory full */
FS_EXIST, /* ( 8) Access denied due to prohibited access */
FS_INVALID_OBJECT, /* ( 9) The file/directory object is invalid */
FS_WRITE_PROTECTED, /* (10) The physical drive is write protected */
FS_INVALID_DRIVE, /* (11) The logical drive number is invalid */
FS_NOT_ENABLED, /* (12) The volume has no work area */
FS_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
FS_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */
FS_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
FS_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
FS_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
FS_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */
FS_INVALID_PARAMETER, /* (19) Given parameter is invalid */
FS_FILE_EMPTY, /* (20) File is empty */
FS_NOT_ENOUGH_MEMORY, /* (21) Not enough memory to malloc file */
} FS_RESULT;
// Changes to this enum should also be made to fs_result_msgs in filesystem.c

FS_RESULT
fs_mount(const DISC_INTERFACE *iface_);
void
fs_unmount();
void
fs_get_volume_label(const char *path, char *label);
FS_RESULT
fs_read_file(void **contents, const char *path);
FS_RESULT
fs_read_file_string(const char **contents, const char *path);
const char *
get_fs_result_message(FS_RESULT result);

#endif
Loading