diff --git a/brewos.iso b/brewos.iso index 958715a..30036f4 100644 Binary files a/brewos.iso and b/brewos.iso differ diff --git a/build/brewos.elf b/build/brewos.elf index 3e08747..e665548 100755 Binary files a/build/brewos.elf and b/build/brewos.elf differ diff --git a/build/cli_apps/fs_commands.o b/build/cli_apps/fs_commands.o index beeec0e..30ab72b 100644 Binary files a/build/cli_apps/fs_commands.o and b/build/cli_apps/fs_commands.o differ diff --git a/build/cmd.o b/build/cmd.o index 145d237..d668243 100644 Binary files a/build/cmd.o and b/build/cmd.o differ diff --git a/build/explorer.o b/build/explorer.o index 6979cbb..2c91de3 100644 Binary files a/build/explorer.o and b/build/explorer.o differ diff --git a/build/minesweeper.o b/build/minesweeper.o index 06b6d90..83db12f 100644 Binary files a/build/minesweeper.o and b/build/minesweeper.o differ diff --git a/build/notepad.o b/build/notepad.o index 9fdc552..aa98857 100644 Binary files a/build/notepad.o and b/build/notepad.o differ diff --git a/iso_root/brewos.elf b/iso_root/brewos.elf index 3e08747..e665548 100755 Binary files a/iso_root/brewos.elf and b/iso_root/brewos.elf differ diff --git a/src/kernel/cli_apps/cli_apps.h b/src/kernel/cli_apps/cli_apps.h index e796f3b..76e5009 100644 --- a/src/kernel/cli_apps/cli_apps.h +++ b/src/kernel/cli_apps/cli_apps.h @@ -27,6 +27,7 @@ void cli_cmd_mkdir(char *args); void cli_cmd_rm(char *args); void cli_cmd_echo(char *args); void cli_cmd_cat(char *args); +void cli_cmd_touch(char *args); // Memory management commands void cli_cmd_meminfo(char *args); diff --git a/src/kernel/cli_apps/fs_commands.c b/src/kernel/cli_apps/fs_commands.c index 54fd790..20b655a 100644 --- a/src/kernel/cli_apps/fs_commands.c +++ b/src/kernel/cli_apps/fs_commands.c @@ -239,3 +239,39 @@ void cli_cmd_cat(char *args) { fat32_close(fh); } + +void cli_cmd_touch(char *args) { + if (!args || args[0] == 0) { + cli_write("Usage: touch \n"); + return; + } + + char filename[256]; + int i = 0; + while (args[i] && args[i] != ' ' && args[i] != '\t') { + filename[i] = args[i]; + i++; + } + filename[i] = 0; + + // Check if file already exists + if (fat32_exists(filename)) { + cli_write("File already exists: "); + cli_write(filename); + cli_write("\n"); + return; + } + + // Open file in write mode to create it + FAT32_FileHandle *fh = fat32_open(filename, "w"); + if (!fh) { + cli_write("Error: Cannot create file\n"); + return; + } + + fat32_close(fh); + + cli_write("Created: "); + cli_write(filename); + cli_write("\n"); +} diff --git a/src/kernel/cmd.c b/src/kernel/cmd.c index ecd6d92..51cd80a 100644 --- a/src/kernel/cmd.c +++ b/src/kernel/cmd.c @@ -14,8 +14,8 @@ #include #include -#define CMD_COLS 70 -#define CMD_ROWS 25 +#define CMD_COLS 116 +#define CMD_ROWS 41 #define LINE_HEIGHT 10 #define CHAR_WIDTH 8 #define PROMPT "> " @@ -108,6 +108,10 @@ static int pager_top_line = 0; // Boot time for uptime int boot_time_init = 0; + +// Output redirection state +static FAT32_FileHandle *redirect_file = NULL; +static char redirect_mode = 0; // '>' for write, 'a' for append, 0 for normal output int boot_year, boot_month, boot_day, boot_hour, boot_min, boot_sec; // --- Helpers --- @@ -193,6 +197,12 @@ static void cmd_scroll_up() { // Public for CLI apps to use void cmd_putchar(char c) { + // If output is being redirected to a file, write there instead + if (redirect_file && redirect_mode) { + fat32_write(redirect_file, &c, 1); + return; + } + if (c == '\n') { cursor_col = 0; cursor_row++; @@ -225,8 +235,14 @@ void cmd_putchar(char c) { // Public for CLI apps to use void cmd_write(const char *str) { - while (*str) { - cmd_putchar(*str++); + // If output is being redirected to a file, write there instead + if (redirect_file && redirect_mode) { + fat32_write(redirect_file, (void *)str, cmd_strlen(str)); + } else { + // Normal output to screen + while (*str) { + cmd_putchar(*str++); + } } } @@ -371,6 +387,8 @@ static const CommandEntry commands[] = { {"echo", cli_cmd_echo}, {"CAT", cli_cmd_cat}, {"cat", cli_cmd_cat}, + {"TOUCH", cli_cmd_touch}, + {"touch", cli_cmd_touch}, // Memory Management Commands {"MEMINFO", cli_cmd_meminfo}, {"meminfo", cli_cmd_meminfo}, @@ -390,7 +408,7 @@ static const CommandEntry commands[] = { // --- Dispatcher --- // Buffer for capturing command output -static char pipe_buffer[4096]; +static char pipe_buffer[8192]; static int pipe_buffer_pos = 0; static void pipe_capture_write(const char *str) { @@ -425,42 +443,73 @@ static void cmd_exec_single(char *cmd) { cmd_write("\n"); } -// Execute command with pipe support +// Execute command with redirection and pipe support static void cmd_exec(char *cmd) { - // Check for pipe operator - char *pipe_ptr = NULL; + // Check for redirection operators (> or >>) + char *redirect_ptr = NULL; + char redirect_op = 0; // '>' or 'a' for append + char output_file[256] = {0}; + int cmd_len = 0; + for (int i = 0; cmd[i]; i++) { - if (cmd[i] == '|' && (i == 0 || cmd[i-1] != '>' && cmd[i+1] != '>' )) { - pipe_ptr = &cmd[i]; + if (cmd[i] == '>' && cmd[i+1] == '>') { + redirect_ptr = cmd + i + 2; + redirect_op = 'a'; // append + cmd_len = i; + break; + } else if (cmd[i] == '>') { + redirect_ptr = cmd + i + 1; + redirect_op = '>'; // write + cmd_len = i; break; } } - if (!pipe_ptr) { - // No pipe - execute normally - cmd_exec_single(cmd); - return; - } - - // Split into two commands - *pipe_ptr = 0; - char *second_cmd = pipe_ptr + 1; - - // Execute first command with output captured - pipe_buffer_pos = 0; - cmd_memset(pipe_buffer, 0, sizeof(pipe_buffer)); - - FAT32_FileHandle *pipe_file = fat32_open("_pipe_temp.tmp", "w"); - if (!pipe_file) { - cmd_write("Error: Cannot create pipe\n"); - return; + // If redirection found, set it up + if (redirect_ptr) { + // Null terminate command + cmd[cmd_len] = 0; + + // Parse output filename + int i = 0; + while (redirect_ptr[i] && (redirect_ptr[i] == ' ' || redirect_ptr[i] == '\t')) { + i++; + } + + int j = 0; + while (redirect_ptr[i] && redirect_ptr[i] != ' ' && redirect_ptr[i] != '\t') { + output_file[j++] = redirect_ptr[i++]; + } + output_file[j] = 0; + + if (!output_file[0]) { + cmd_write("Error: No output file specified\n"); + return; + } + + // Open file for redirection + const char *mode = (redirect_op == 'a') ? "a" : "w"; + redirect_file = fat32_open(output_file, mode); + if (!redirect_file) { + cmd_write("Error: Cannot open file for redirection\n"); + return; + } + + redirect_mode = redirect_op; } + // Execute the command cmd_exec_single(cmd); - fat32_close(pipe_file); - - cmd_exec_single(second_cmd); + // Close redirected file if it was opened + if (redirect_file) { + fat32_close(redirect_file); + redirect_file = NULL; + redirect_mode = 0; + cmd_write("Output redirected to: "); + cmd_write(output_file); + cmd_write("\n"); + } } diff --git a/src/kernel/explorer.c b/src/kernel/explorer.c index bcbf272..0e83140 100644 --- a/src/kernel/explorer.c +++ b/src/kernel/explorer.c @@ -335,21 +335,28 @@ static void explorer_paint(Window *win) { // Draw icon (larger area) explorer_draw_file_icon(item_x + 5, item_y + 5, items[i].is_directory); - // Draw name below icon + // Draw name below icon with text wrapping uint32_t text_color = (i == selected_item) ? COLOR_WHITE : COLOR_BLACK; int name_len = explorer_strlen(items[i].name); int text_x = item_x + 5; int text_y = item_y + 50; + int max_name_width = EXPLORER_ITEM_WIDTH - 10; // 110 pixels available for text + int chars_per_line = max_name_width / 8; // 8 pixels per character - // Truncate name if too long - char display_name[24]; - int copy_len = name_len > 18 ? 18 : name_len; - for (int j = 0; j < copy_len; j++) { - display_name[j] = items[i].name[j]; + // Draw wrapped filename + int line_offset = 0; + char line_buffer[25]; + for (int j = 0; j < name_len; j++) { + int pos_in_line = j % chars_per_line; + line_buffer[pos_in_line] = items[i].name[j]; + line_buffer[pos_in_line + 1] = 0; + + // Draw line when we reach end of line or end of name + if (pos_in_line == chars_per_line - 1 || j == name_len - 1) { + draw_string(text_x, text_y + (line_offset * 10), line_buffer, text_color); + line_offset++; + } } - display_name[copy_len] = 0; - - draw_string(text_x, text_y, display_name, text_color); } // Draw dialogs diff --git a/src/kernel/minesweeper.c b/src/kernel/minesweeper.c index 78f9ff3..1c4cf0c 100644 --- a/src/kernel/minesweeper.c +++ b/src/kernel/minesweeper.c @@ -160,7 +160,7 @@ static void minesweeper_paint(Window *win) { } else if (game_won) { draw_string(win->x + 10, win->y + 30, "You Won!", COLOR_BLUE); } else { - draw_string(win->x + 10, win->y + 30, "Minesweeper", COLOR_BLACK); + draw_string(win->x + 10, win->y + 30, "", COLOR_BLACK); } // Draw grid