diff --git a/Makefile b/Makefile index 2b83ea7..005c5ee 100755 --- a/Makefile +++ b/Makefile @@ -41,6 +41,7 @@ OBJS = $(addprefix $(BUILD)/$(TARGET)/, \ se.o \ tsec.o \ uart.o \ + dirlist.o \ ini.o \ ianos.o \ ) diff --git a/bootloader/config/config.c b/bootloader/config/config.c index 13cb9d1..3312028 100644 --- a/bootloader/config/config.c +++ b/bootloader/config/config.c @@ -39,6 +39,7 @@ extern int sd_unmount(); void set_default_configuration() { h_cfg.autoboot = 0; + h_cfg.autoboot_list = 0; h_cfg.bootwait = 3; h_cfg.customlogo = 0; h_cfg.verification = 2; @@ -56,7 +57,7 @@ int create_config_entry() LIST_INIT(ini_sections); - if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini")) + if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) { if (f_open(&fp, "bootloader/hekate_ipl.ini", FA_WRITE | FA_CREATE_ALWAYS) != FR_OK) return 0; @@ -64,6 +65,9 @@ int create_config_entry() f_puts("[config]\nautoboot=", &fp); itoa(h_cfg.autoboot, lbuf, 10); f_puts(lbuf, &fp); + f_puts("\nautoboot_list=", &fp); + itoa(h_cfg.autoboot_list, lbuf, 10); + f_puts(lbuf, &fp); f_puts("\nbootwait=", &fp); itoa(h_cfg.bootwait, lbuf, 10); f_puts(lbuf, &fp); @@ -123,7 +127,7 @@ int create_config_entry() return 0; } -void config_autoboot() +void _config_autoboot_list() { gfx_clear_grey(&gfx_ctxt, 0x1B); gfx_con_setpos(&gfx_con, 0, 0); @@ -143,7 +147,112 @@ void config_autoboot() if (sd_mount()) { - if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini")) + if (ini_parse(&ini_sections, "bootloader/ini", true)) + { + // Build configuration menu. + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + + ments[1].type = MENT_CHGLINE; + + u32 i = 2; + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) + { + // Skip other ini entries for autoboot. + if (ini_sec->type == INI_CHOICE) + { + if (!strcmp(ini_sec->name, "config")) + continue; + + if (strlen(ini_sec->name) > 510) + ments[i].caption = ini_sec->name; + else + { + if (h_cfg.autoboot != (i - 1) || !h_cfg.autoboot_list) + boot_text[(i - 1) * 512] = ' '; + + else + boot_text[(i - 1) * 512] = '*'; + memcpy(boot_text + (i - 1) * 512 + 1, ini_sec->name, strlen(ini_sec->name)); + boot_text[strlen(ini_sec->name) + (i - 1) * 512 + 1] = 0; + ments[i].caption = &boot_text[(i - 1) * 512]; + } + ments[i].type = ini_sec->type; + ments[i].data = &boot_values[i - 1]; + i++; + + if ((i - 1) > max_entries) + break; + } + } + if (i < 3) + { + EPRINTF("No launch configurations found."); + goto out; + } + + memset(&ments[i], 0, sizeof(ment_t)); + menu_t menu = {ments, "Select a list entry to auto boot", 0, 0}; + temp_autoboot = (u32 *)tui_do_menu(&gfx_con, &menu); + if (temp_autoboot != NULL) + { + gfx_clear_grey(&gfx_ctxt, 0x1B); + gfx_con_setpos(&gfx_con, 0, 0); + + h_cfg.autoboot = *(u32 *)temp_autoboot; + h_cfg.autoboot_list = 1; + // Save choice to ini file. + if (!create_config_entry()) + gfx_puts(&gfx_con, "\nConfiguration was saved!\n"); + else + EPRINTF("\nConfiguration saving failed!"); + gfx_puts(&gfx_con, "\nPress any key..."); + } + else + goto out2; + } + else + { + EPRINTF("Could not find or open 'hekate_ipl.ini'.\nMake sure it exists in SD Card!."); + goto out; + } + } + +out:; + btn_wait(); +out2:; + free(ments); + free(boot_values); + free(boot_text); + ini_free(&ini_sections); + + sd_unmount(); + + if (temp_autoboot == NULL) + return; +} + +void config_autoboot() +{ + gfx_clear_grey(&gfx_ctxt, 0x1B); + gfx_con_setpos(&gfx_con, 0, 0); + + u32 *temp_autoboot = NULL; + + LIST_INIT(ini_sections); + + u8 max_entries = 30; + + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 5)); + u32 *boot_values = (u32 *)malloc(sizeof(u32) * max_entries); + char *boot_text = (char *)malloc(512 * max_entries); + + for (u32 j = 0; j < max_entries; j++) + boot_values[j] = j; + + if (sd_mount()) + { + if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) { // Build configuration menu. ments[0].type = MENT_BACK; @@ -158,7 +267,17 @@ void config_autoboot() ments[2].caption = " Disable"; ments[2].data = &boot_values[0]; - u32 i = 3; + ments[3].type = MENT_HANDLER; + if (h_cfg.autoboot_list) + ments[3].caption = "*More configs..."; + else + ments[3].caption = " More configs..."; + ments[3].handler = _config_autoboot_list; + ments[3].data = NULL; + + ments[4].type = MENT_CHGLINE; + + u32 i = 5; LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) { // Skip other ini entries for autoboot. @@ -171,24 +290,24 @@ void config_autoboot() ments[i].caption = ini_sec->name; else { - if (h_cfg.autoboot != (i - 2)) - boot_text[(i - 2) * 512] = ' '; + if (h_cfg.autoboot != (i - 4) || h_cfg.autoboot_list) + boot_text[(i - 4) * 512] = ' '; else - boot_text[(i - 2) * 512] = '*'; - memcpy(boot_text + (i - 2) * 512 + 1, ini_sec->name, strlen(ini_sec->name)); - boot_text[strlen(ini_sec->name) + (i - 2) * 512 + 1] = 0; - ments[i].caption = &boot_text[(i - 2) * 512]; + boot_text[(i - 4) * 512] = '*'; + memcpy(boot_text + (i - 4) * 512 + 1, ini_sec->name, strlen(ini_sec->name)); + boot_text[strlen(ini_sec->name) + (i - 4) * 512 + 1] = 0; + ments[i].caption = &boot_text[(i - 4) * 512]; } ments[i].type = ini_sec->type; - ments[i].data = &boot_values[i - 2]; + ments[i].data = &boot_values[i - 4]; i++; - if (i > max_entries) + if ((i - 4) > max_entries) break; } } - if (i < 4) + if (i < 6 && !h_cfg.autoboot_list) { EPRINTF("No launch configurations found."); goto out; @@ -203,6 +322,7 @@ void config_autoboot() gfx_con_setpos(&gfx_con, 0, 0); h_cfg.autoboot = *(u32 *)temp_autoboot; + h_cfg.autoboot_list = 0; // Save choice to ini file. if (!create_config_entry()) gfx_puts(&gfx_con, "\nConfiguration was saved!\n"); diff --git a/bootloader/config/config.h b/bootloader/config/config.h index a3bbd7b..a50132a 100644 --- a/bootloader/config/config.h +++ b/bootloader/config/config.h @@ -22,6 +22,7 @@ typedef struct _hekate_config { u32 autoboot; + u32 autoboot_list; u32 bootwait; u32 customlogo; u32 verification; diff --git a/bootloader/config/ini.c b/bootloader/config/ini.c index 54b25b6..80e3acf 100644 --- a/bootloader/config/ini.c +++ b/bootloader/config/ini.c @@ -20,119 +20,162 @@ #include "ini.h" #include "../libs/fatfs/ff.h" #include "../mem/heap.h" +#include "../utils/dirlist.h" static char *_strdup(char *str) { - char *res = malloc(strlen(str) + 1); + char *res = (char *)malloc(strlen(str) + 1); strcpy(res, str); return res; } -int ini_parse(link_t *dst, char *ini_path) +int ini_parse(link_t *dst, char *ini_path, bool is_dir) { u32 lblen; + u32 pathlen = strlen(ini_path); + u32 k = 0; char lbuf[512]; + char *filelist = NULL; FIL fp; ini_sec_t *csec = NULL; - if (f_open(&fp, ini_path, FA_READ) != FR_OK) - return 0; + char *filename = (char *)malloc(256); + + memcpy(filename, ini_path, pathlen + 1); + + if (is_dir) + { + filelist = dirlist(filename); + if (!filelist) + { + free(filename); + return 0; + } + memcpy(filename + pathlen, "/", 2); + pathlen++; + } do { - // Fetch one line. - lbuf[0] = 0; - f_gets(lbuf, 512, &fp); - lblen = strlen(lbuf); - - // Remove trailing newline. - if (lbuf[lblen - 1] == '\n') - lbuf[lblen - 1] = 0; - - if (lblen > 2 && lbuf[0] == '[') // Create new section. + if (is_dir) { - if (csec) + if (filelist[k * 256]) { - list_append(dst, &csec->link); - csec = NULL; + memcpy(filename + pathlen, &filelist[k * 256], strlen(&filelist[k * 256]) + 1); + k++; } - - u32 i; - for (i = 0; i < lblen && lbuf[i] != '\n' && lbuf[i] != ']'; i++) - ; - lbuf[i] = 0; - - csec = (ini_sec_t *)malloc(sizeof(ini_sec_t)); - csec->name = _strdup(&lbuf[1]); - csec->type = INI_CHOICE; - list_init(&csec->kvs); + else + break; } - else if (lblen > 2 && lbuf[0] == '{') //Create new caption. + + if (f_open(&fp, filename, FA_READ) != FR_OK) { - if (csec) + free(filelist); + free(filename); + + return 0; + } + + do + { + // Fetch one line. + lbuf[0] = 0; + f_gets(lbuf, 512, &fp); + lblen = strlen(lbuf); + + // Remove trailing newline. + if (lbuf[lblen - 1] == '\n') + lbuf[lblen - 1] = 0; + + if (lblen > 2 && lbuf[0] == '[') // Create new section. { - list_append(dst, &csec->link); - csec = NULL; + if (csec) + { + list_append(dst, &csec->link); + csec = NULL; + } + + u32 i; + for (i = 0; i < lblen && lbuf[i] != '\n' && lbuf[i] != ']'; i++) + ; + lbuf[i] = 0; + + csec = (ini_sec_t *)malloc(sizeof(ini_sec_t)); + csec->name = _strdup(&lbuf[1]); + csec->type = INI_CHOICE; + list_init(&csec->kvs); } - - u32 i; - for (i = 0; i < lblen && lbuf[i] != '\n' && lbuf[i] != '}'; i++) - ; - lbuf[i] = 0; - - csec = (ini_sec_t *)malloc(sizeof(ini_sec_t)); - csec->name = _strdup(&lbuf[1]); - csec->type = INI_CAPTION; - csec->color = 0xFF0AB9E6; - } - else if (lblen > 2 && lbuf[0] == '#') //Create empty lines and comments. - { - if (csec) + else if (lblen > 2 && lbuf[0] == '{') //Create new caption. { - list_append(dst, &csec->link); - csec = NULL; + if (csec) + { + list_append(dst, &csec->link); + csec = NULL; + } + + u32 i; + for (i = 0; i < lblen && lbuf[i] != '\n' && lbuf[i] != '}'; i++) + ; + lbuf[i] = 0; + + csec = (ini_sec_t *)malloc(sizeof(ini_sec_t)); + csec->name = _strdup(&lbuf[1]); + csec->type = INI_CAPTION; + csec->color = 0xFF0AB9E6; } - - u32 i; - for (i = 0; i < lblen && lbuf[i] != '\n'; i++) - ; - lbuf[i] = 0; - - csec = (ini_sec_t *)malloc(sizeof(ini_sec_t)); - csec->name = _strdup(&lbuf[1]); - csec->type = INI_COMMENT; - } - else if (lblen <= 1) - { - if (csec) + else if (lblen > 2 && lbuf[0] == '#') //Create empty lines and comments. { - list_append(dst, &csec->link); - csec = NULL; + if (csec) + { + list_append(dst, &csec->link); + csec = NULL; + } + + u32 i; + for (i = 0; i < lblen && lbuf[i] != '\n'; i++) + ; + lbuf[i] = 0; + + csec = (ini_sec_t *)malloc(sizeof(ini_sec_t)); + csec->name = _strdup(&lbuf[1]); + csec->type = INI_COMMENT; } + else if (lblen < 2) + { + if (csec) + { + list_append(dst, &csec->link); + csec = NULL; + } - csec = (ini_sec_t *)malloc(sizeof(ini_sec_t)); - csec->name = NULL; - csec->type = INI_NEWLINE; - } - else if (csec->type == INI_CHOICE) //Extract key/value. - { - u32 i; - for (i = 0; i < lblen && lbuf[i] != '\n' && lbuf[i] != '='; i++) - ; - lbuf[i] = 0; + csec = (ini_sec_t *)malloc(sizeof(ini_sec_t)); + csec->name = NULL; + csec->type = INI_NEWLINE; + } + else if (csec->type == INI_CHOICE) //Extract key/value. + { + u32 i; + for (i = 0; i < lblen && lbuf[i] != '\n' && lbuf[i] != '='; i++) + ; + lbuf[i] = 0; - ini_kv_t *kv = (ini_kv_t *)malloc(sizeof(ini_kv_t)); - kv->key = _strdup(&lbuf[0]); - kv->val = _strdup(&lbuf[i + 1]); - list_append(&csec->kvs, &kv->link); - } - } while (!f_eof(&fp)); + ini_kv_t *kv = (ini_kv_t *)malloc(sizeof(ini_kv_t)); + kv->key = _strdup(&lbuf[0]); + kv->val = _strdup(&lbuf[i + 1]); + list_append(&csec->kvs, &kv->link); + } + } while (!f_eof(&fp)); - f_close(&fp); + f_close(&fp); + + } while (is_dir); if (csec) list_append(dst, &csec->link); + free(filename); + free(filelist); + return 1; } diff --git a/bootloader/config/ini.h b/bootloader/config/ini.h index d993992..db08cd1 100644 --- a/bootloader/config/ini.h +++ b/bootloader/config/ini.h @@ -43,7 +43,7 @@ typedef struct _ini_sec_t u32 color; } ini_sec_t; -int ini_parse(link_t *dst, char *ini_path); +int ini_parse(link_t *dst, char *ini_path, bool is_dir); void ini_free(link_t *dst); ini_sec_t *ini_clone_section(ini_sec_t *cfg); void ini_free_section(ini_sec_t *cfg); diff --git a/bootloader/hos/hos.c b/bootloader/hos/hos.c index b216eb1..346b988 100644 --- a/bootloader/hos/hos.c +++ b/bootloader/hos/hos.c @@ -390,7 +390,7 @@ static int _config_kip1patch(launch_ctxt_t *ctxt, const char *value) return 0; int valueLen = strlen(value); - if (valueLen == 0) + if (!valueLen) return 0; if (ctxt->kip1_patches == NULL) @@ -435,10 +435,15 @@ static const cfg_handler_t _config_handlers[] = { static int _config(launch_ctxt_t *ctxt, ini_sec_t *cfg) { LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg->kvs, link) + { for(u32 i = 0; _config_handlers[i].key; i++) - if (!strcmp(_config_handlers[i].key, kv->key) && - !_config_handlers[i].handler(ctxt, kv->val)) - return 0; + { + if (!strcmp(_config_handlers[i].key, kv->key)) + if (!_config_handlers[i].handler(ctxt, kv->val)) + return 0; + } + } + return 1; } @@ -667,7 +672,7 @@ int hos_launch(ini_sec_t *cfg) // Wait for secmon to get ready. cluster_boot_cpu0(ctxt.pkg1_id->secmon_base); while (!*mb_out) - ; + usleep(1); // This only works when in IRAM or with a trained DRAM. //TODO: pkg1.1 locks PMC scratches, we can do that too at some point. /*PMC(0x4) = 0x7FFFF3; diff --git a/bootloader/main.c b/bootloader/main.c index 5d88262..2459c8b 100644 --- a/bootloader/main.c +++ b/bootloader/main.c @@ -57,6 +57,7 @@ #include "power/bq24193.h" #include "config/config.h" #include "ianos/ianos.h" +#include "utils/dirlist.h" //TODO: ugly. gfx_ctxt_t gfx_ctxt; @@ -1720,6 +1721,102 @@ out: btn_wait(); } +void ini_list_launcher() +{ + u8 max_entries = 61; + char *payload_path = NULL; + + ini_sec_t *cfg_sec = NULL; + LIST_INIT(ini_list_sections); + + gfx_clear_grey(&gfx_ctxt, 0x1B); + gfx_con_setpos(&gfx_con, 0, 0); + + if (sd_mount()) + { + if (ini_parse(&ini_list_sections, "bootloader/ini", true)) + { + // Build configuration menu. + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3)); + ments[0].type = MENT_BACK; + ments[0].caption = "Back"; + ments[1].type = MENT_CHGLINE; + + u32 i = 2; + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_list_sections, link) + { + if (!strcmp(ini_sec->name, "config") || + ini_sec->type == INI_COMMENT || ini_sec->type == INI_NEWLINE) + continue; + ments[i].type = ini_sec->type; + ments[i].caption = ini_sec->name; + ments[i].data = ini_sec; + if (ini_sec->type == MENT_CAPTION) + ments[i].color = ini_sec->color; + i++; + + if ((i - 1) > max_entries) + break; + } + if (i > 2) + { + memset(&ments[i], 0, sizeof(ment_t)); + menu_t menu = { + ments, "Launch ini configurations", 0, 0 + }; + cfg_sec = ini_clone_section((ini_sec_t *)tui_do_menu(&gfx_con, &menu)); + if (!cfg_sec) + { + free(ments); + ini_free(&ini_list_sections); + + return; + } + } + else + EPRINTF("No ini configurations found."); + free(ments); + //ini_free(&ini_list_sections); // This breaks hos_launch config parsing. + } + else + EPRINTF("Could not find any ini\nin bootloader/ini folder!"); + } + + if (!cfg_sec) + goto out; + +#ifdef MENU_LOGO_ENABLE + free(Kc_MENU_LOGO); +#endif //MENU_LOGO_ENABLE + + payload_path = ini_check_payload_section(cfg_sec); + + if (payload_path) + { + ini_free_section(cfg_sec); + //if (launch_payload(payload_path, false)) + //{ + EPRINTF("Failed to launch payload."); + free(payload_path); + //} + } + else if (!hos_launch(cfg_sec)) + { + EPRINTF("Failed to launch firmware."); + btn_wait(); + } + +#ifdef MENU_LOGO_ENABLE + Kc_MENU_LOGO = (u8 *)malloc(0x6000); + blz_uncompress_srcdest(Kc_MENU_LOGO_blz, SZ_MENU_LOGO_BLZ, Kc_MENU_LOGO, SZ_MENU_LOGO); +#endif //MENU_LOGO_ENABLE + +out: + ini_free_section(cfg_sec); + + btn_wait(); +} + void launch_firmware() { u8 max_entries = 61; @@ -1732,15 +1829,21 @@ void launch_firmware() if (sd_mount()) { - if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini")) + if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) { // Build configuration menu. - ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 3)); + ment_t *ments = (ment_t *)malloc(sizeof(ment_t) * (max_entries + 5)); ments[0].type = MENT_BACK; ments[0].caption = "Back"; ments[1].type = MENT_CHGLINE; - u32 i = 2; + ments[2].type = MENT_HANDLER; + ments[2].caption = "More configs..."; + ments[2].handler = ini_list_launcher; + + ments[3].type = MENT_CHGLINE; + + u32 i = 4; LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link) { if (!strcmp(ini_sec->name, "config") || @@ -1753,10 +1856,10 @@ void launch_firmware() ments[i].color = ini_sec->color; i++; - if (i > max_entries) + if ((i - 3) > max_entries) break; } - if (i > 2) + if (i > 4) { memset(&ments[i], 0, sizeof(ment_t)); menu_t menu = { @@ -1828,12 +1931,15 @@ void auto_launch_firmware() ini_sec_t *cfg_sec = NULL; LIST_INIT(ini_sections); + LIST_INIT(ini_list_sections); gfx_con.mute = true; if (sd_mount()) { - if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini")) + auto_launch_update(); + + if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false)) { u32 configEntry = 0; u32 boot_entry_id = 0; @@ -1851,6 +1957,8 @@ void auto_launch_firmware() { if (!strcmp("autoboot", kv->key)) h_cfg.autoboot = atoi(kv->val); + else if (!strcmp("autoboot_list", kv->key)) + h_cfg.autoboot_list = atoi(kv->val); else if (!strcmp("bootwait", kv->key)) h_cfg.bootwait = atoi(kv->val); else if (!strcmp("customlogo", kv->key)) @@ -1869,6 +1977,7 @@ void auto_launch_firmware() { if (!strcmp("logopath", kv->key)) bootlogoCustomEntry = kv->val; + gfx_printf(&gfx_con, "\n%s=%s\n\n", kv->key, kv->val); } break; } @@ -1876,6 +1985,43 @@ void auto_launch_firmware() } } + if (h_cfg.autoboot_list) + { + ini_free(&ini_sections); + list_init(&ini_sections); + ini_free_section(cfg_sec); + boot_entry_id = 1; + bootlogoCustomEntry = NULL; + + if (ini_parse(&ini_list_sections, "bootloader/ini", true)) + { + LIST_FOREACH_ENTRY(ini_sec_t, ini_sec_list, &ini_list_sections, link) + { + if (ini_sec_list->type == INI_CHOICE) + { + if (!strcmp(ini_sec_list->name, "config")) + continue; + + if (h_cfg.autoboot == boot_entry_id) + { + cfg_sec = ini_clone_section(ini_sec_list); + LIST_FOREACH_ENTRY(ini_kv_t, kv, &cfg_sec->kvs, link) + { + if (!strcmp("logopath", kv->key)) + bootlogoCustomEntry = kv->val; + gfx_printf(&gfx_con, "\n%s=%s\n\n", kv->key, kv->val); + } + break; + } + boot_entry_id++; + } + + } + + } + + } + // Add missing configuration entry. if (!configEntry) create_config_entry(); @@ -1969,6 +2115,8 @@ void auto_launch_firmware() goto out; ini_free(&ini_sections); + if (h_cfg.autoboot_list) + ini_free(&ini_list_sections); #ifdef MENU_LOGO_ENABLE free(Kc_MENU_LOGO); @@ -1985,6 +2133,8 @@ void auto_launch_firmware() out: gfx_clear_grey(&gfx_ctxt, 0x1B); ini_free(&ini_sections); + if (h_cfg.autoboot_list) + ini_free(&ini_list_sections); ini_free_section(cfg_sec); sd_unmount(); @@ -2581,7 +2731,7 @@ menu_t menu_tools = { }; ment_t ment_top[] = { - MDEF_HANDLER("Launch firmware", launch_firmware), + MDEF_HANDLER("Launch", launch_firmware), MDEF_MENU("Launch options", &menu_options), MDEF_CAPTION("---------------", 0xFF444444), MDEF_MENU("Tools", &menu_tools), diff --git a/bootloader/utils/dirlist.c b/bootloader/utils/dirlist.c new file mode 100644 index 0000000..5c01cd9 --- /dev/null +++ b/bootloader/utils/dirlist.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include + +#include "../libs/fatfs/ff.h" +#include "../mem/heap.h" +#include "../utils/types.h" + +char *dirlist(char *directory) +{ + u8 max_entries = 61; + + int res = 0; + u32 i = 0, j = 0, k = 0; + DIR dir; + static FILINFO fno; + + char *dir_entries = (char *)calloc(max_entries, 256); + char *temp = (char *)calloc(1, 256); + + if (!f_opendir(&dir, directory)) + { + for (;;) + { + res = f_readdir(&dir, &fno); + if (res || !fno.fname[0]) + break; + if (!(fno.fattrib & AM_DIR)) + { + memcpy(dir_entries + (k * 256), fno.fname, strlen(fno.fname) + 1); + k++; + if (k > (max_entries - 1)) + break; + } + else + continue; + } + f_closedir(&dir); + } + else + return NULL; + + for (i = 0; i < k - 1 ; i++) + { + for (j = i + 1; j < k; j++) + { + if (strcmp(&dir_entries[i * 256], &dir_entries[j * 256]) > 0) + { + memcpy(temp, &dir_entries[i * 256], strlen(&dir_entries[i * 256]) + 1); + memcpy(&dir_entries[i * 256], &dir_entries[j * 256], strlen(&dir_entries[j * 256]) + 1); + memcpy(&dir_entries[j * 256], temp, strlen(temp) + 1); + } + } + } + + free(temp); + + return dir_entries; +} diff --git a/bootloader/utils/dirlist.h b/bootloader/utils/dirlist.h new file mode 100644 index 0000000..e1510e9 --- /dev/null +++ b/bootloader/utils/dirlist.h @@ -0,0 +1,19 @@ +/* + * Copyright (c) 2018 CTCaer + * + * This program is free software; you can redistribute it and/or modify it + * under the terms and conditions of the GNU General Public License, + * version 2, as published by the Free Software Foundation. + * + * This program is distributed in the hope it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "../utils/types.h" + +char *dirlist(char *directory);