297 lines
6.3 KiB
C
297 lines
6.3 KiB
C
|
#include <ncurses.h>
|
||
|
#include <string.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <ctype.h>
|
||
|
#include <stdio.h>
|
||
|
|
||
|
|
||
|
typedef struct {
|
||
|
const char* name;
|
||
|
int enabled;
|
||
|
} option_t;
|
||
|
|
||
|
typedef struct {
|
||
|
const char* title;
|
||
|
option_t* options;
|
||
|
size_t num_options;
|
||
|
} menu_t;
|
||
|
|
||
|
void show_menu(menu_t* menu);
|
||
|
void load_config(menu_t* menus, size_t menu_count);
|
||
|
void save_config(menu_t* menus, size_t menu_count);
|
||
|
|
||
|
#define SIZE(x) (sizeof(x) / sizeof(option_t))
|
||
|
#define NUM_MENUS (sizeof(all_menus) / sizeof(menu_t))
|
||
|
#define KEY_ESCAPE 27
|
||
|
|
||
|
option_t general_opts[] = {
|
||
|
{ "Enable Debugging Messages", 1 },
|
||
|
{ "Enable Filesystems", 0 },
|
||
|
};
|
||
|
|
||
|
option_t drivers_opts[] = {
|
||
|
{ "Enable IDE", 1 },
|
||
|
{ "Enable USB", 0 },
|
||
|
{ "Enable Network", 0 },
|
||
|
};
|
||
|
|
||
|
menu_t all_menus[] = {
|
||
|
{ "General Settings", general_opts, SIZE(general_opts) },
|
||
|
{ "Device Drivers", drivers_opts, SIZE(drivers_opts) },
|
||
|
};
|
||
|
|
||
|
bool current_config_saved = false;
|
||
|
|
||
|
void strfix(char *str)
|
||
|
{
|
||
|
for (size_t i = 0; str[i] != '\0'; ++i)
|
||
|
{
|
||
|
if (isspace((unsigned char)str[i]))
|
||
|
{
|
||
|
str[i] = '_';
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
str[i] = toupper((unsigned char)str[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void load_config(menu_t* menus, size_t menu_count)
|
||
|
{
|
||
|
FILE* f = fopen(".config", "r");
|
||
|
if (!f)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
char line[128];
|
||
|
while (fgets(line, sizeof(line), f))
|
||
|
{
|
||
|
char* newline = strchr(line, '\n');
|
||
|
if (newline)
|
||
|
{
|
||
|
*newline = 0;
|
||
|
}
|
||
|
|
||
|
for (size_t m = 0; m < menu_count; m++)
|
||
|
{
|
||
|
for (size_t i = 0; i < menus[m].num_options; i++)
|
||
|
{
|
||
|
if (strncmp(line, menus[m].options[i].name, strlen(menus[m].options[i].name)) == 0)
|
||
|
{
|
||
|
if (strstr(line, "=y"))
|
||
|
{
|
||
|
menus[m].options[i].enabled = 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
menus[m].options[i].enabled = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fclose(f);
|
||
|
}
|
||
|
|
||
|
const char* cc = "\n\nstatic inline kconf_t get_kconfig(void)\n"
|
||
|
"{\n"
|
||
|
"\tkconf_t kc = { false, false, false, false, false };\n\n"
|
||
|
"#ifdef ENABLE_DEBUGGING_MESSAGES\n"
|
||
|
"\tkc.enable_debug = true;\n"
|
||
|
"#endif\n"
|
||
|
"#ifdef ENABLE_FILESYSTEMS\n"
|
||
|
"\tkc.enable_fs = true;\n"
|
||
|
"#endif\n"
|
||
|
"#ifdef ENABLE_IDE\n"
|
||
|
"\tkc.enable_ide = true;\n"
|
||
|
"#endif\n"
|
||
|
"#ifdef ENABLE_USB\n"
|
||
|
"\tkc.enable_usb = true;\n"
|
||
|
"#endif\n"
|
||
|
"#ifdef ENABLE_NETWORK\n"
|
||
|
"\tkc.enable_networking = true;\n"
|
||
|
"#endif\n\n"
|
||
|
"\treturn kc;\n"
|
||
|
"}\n\n"
|
||
|
"#ifdef __cplusplus\n"
|
||
|
"}\n"
|
||
|
"#endif\n";
|
||
|
|
||
|
/* Save current configuration options to Makefile and/or kconfig.h */
|
||
|
void save_config(menu_t* menus, size_t menu_count)
|
||
|
{
|
||
|
FILE* kconff = fopen("../include/kernel/kconfig.h", "w");
|
||
|
|
||
|
if (!kconff)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
const char* hg = "#ifndef _KCONFIG_H\n#define _KCONFIG_H\n\n#include <types.h>\n\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n\n";
|
||
|
|
||
|
|
||
|
fprintf(kconff, hg);
|
||
|
|
||
|
for (size_t m = 0; m < menu_count; m++)
|
||
|
{
|
||
|
for (size_t i = 0; i < menus[m].num_options; i++)
|
||
|
{
|
||
|
|
||
|
char buffer[128];
|
||
|
strncpy(buffer, menus[m].options[i].name, sizeof(buffer));
|
||
|
buffer[sizeof(buffer)-1] = '\0';
|
||
|
strfix(buffer);
|
||
|
|
||
|
if (menus[m].options[i].enabled == 0)
|
||
|
{
|
||
|
fprintf(kconff, "//");
|
||
|
}
|
||
|
|
||
|
fprintf(kconff, "#define %s\n", buffer, menus[m].options[i].enabled);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fprintf(kconff, cc);
|
||
|
|
||
|
fprintf(kconff, "\n#endif\n");
|
||
|
|
||
|
fclose(kconff);
|
||
|
|
||
|
current_config_saved = true;
|
||
|
}
|
||
|
|
||
|
menu_t* create_menu(const char* title)
|
||
|
{
|
||
|
menu_t* menu = malloc(sizeof(menu_t));
|
||
|
menu->title = strdup(title);
|
||
|
menu->options = NULL;
|
||
|
menu->num_options = 0;
|
||
|
return menu;
|
||
|
}
|
||
|
|
||
|
void add_option(menu_t* menu, const char* name, int default_value)
|
||
|
{
|
||
|
menu->options = realloc(menu->options, sizeof(option_t) * (menu->num_options + 1));
|
||
|
menu->options[menu->num_options].name = strdup(name);
|
||
|
menu->options[menu->num_options].enabled = default_value;
|
||
|
menu->num_options++;
|
||
|
}
|
||
|
|
||
|
|
||
|
/* Display a single submenu */
|
||
|
void show_menu(menu_t* menu)
|
||
|
{
|
||
|
int selected = 0;
|
||
|
|
||
|
while (1)
|
||
|
{
|
||
|
clear();
|
||
|
mvprintw(0, 0, "%s (SPACE=toggle, (left arrow key or esc)=back, S=save)", menu->title);
|
||
|
|
||
|
for (size_t i = 0; i < menu->num_options; i++)
|
||
|
{
|
||
|
if ((int)i == selected)
|
||
|
{
|
||
|
attron(A_REVERSE);
|
||
|
}
|
||
|
mvprintw(i + 2, 2, "[%c] %s", menu->options[i].enabled ? 'X' : ' ', menu->options[i].name);
|
||
|
if ((int)i == selected)
|
||
|
{
|
||
|
attroff(A_REVERSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int ch = getch();
|
||
|
|
||
|
if (ch == KEY_UP && selected > 0)
|
||
|
{
|
||
|
selected--;
|
||
|
}
|
||
|
else if (ch == KEY_DOWN && selected < (int)menu->num_options - 1)
|
||
|
{
|
||
|
selected++;
|
||
|
}
|
||
|
else if (ch == ' ')
|
||
|
{
|
||
|
menu->options[selected].enabled = !menu->options[selected].enabled;
|
||
|
current_config_saved = false;
|
||
|
}
|
||
|
else if (ch == 's' || ch == 'S')
|
||
|
{
|
||
|
save_config(all_menus, NUM_MENUS);
|
||
|
mvprintw(menu->num_options + 3, 2, "Saved.");
|
||
|
refresh();
|
||
|
getch();
|
||
|
}
|
||
|
else if (ch == KEY_LEFT || ch == KEY_ESCAPE || ch == 'q' || ch == 'Q')
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Main menu with submenu navigation */
|
||
|
int main(void)
|
||
|
{
|
||
|
initscr();
|
||
|
noecho();
|
||
|
cbreak();
|
||
|
keypad(stdscr, TRUE);
|
||
|
set_escdelay(25); /* wait only 25ms for escape sequences */
|
||
|
|
||
|
/*load_config(all_menus, NUM_MENUS);*/
|
||
|
|
||
|
int selected = 0;
|
||
|
while (1)
|
||
|
{
|
||
|
clear();
|
||
|
mvprintw(0, 0, "Kernel Configuration (ENTER=submenu, S=save, Q=quit)");
|
||
|
|
||
|
for (size_t i = 0; i < NUM_MENUS; i++)
|
||
|
{
|
||
|
if ((int)i == selected)
|
||
|
{
|
||
|
attron(A_REVERSE);
|
||
|
}
|
||
|
mvprintw(i + 2, 2, "> %s", all_menus[i].title);
|
||
|
if ((int)i == selected)
|
||
|
{
|
||
|
attroff(A_REVERSE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int ch = getch();
|
||
|
|
||
|
if (ch == KEY_UP && selected > 0)
|
||
|
{
|
||
|
selected--;
|
||
|
}
|
||
|
else if (ch == KEY_DOWN && selected < (int)NUM_MENUS - 1)
|
||
|
{
|
||
|
selected++;
|
||
|
}
|
||
|
else if (ch == '\n')
|
||
|
{
|
||
|
show_menu(&all_menus[selected]);
|
||
|
}
|
||
|
else if (ch == 's' || ch == 'S')
|
||
|
{
|
||
|
save_config(all_menus, NUM_MENUS);
|
||
|
mvprintw(NUM_MENUS + 3, 2, "Saved.");
|
||
|
refresh();
|
||
|
getch();
|
||
|
}
|
||
|
else if (ch == 'q' || ch == 'Q')
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
endwin();
|
||
|
return 0;
|
||
|
}
|
||
|
|