added advanced ls support
using ls now creates a table and populates it with entries. added piping to ls so filter the search (credits to nuShell for the idea) ls | contains name xxx to ls for only entries containing the string ls | where size < or > 10mb, kb, gb etc ls | select name, size modified type. select which collums you want to see in the result
This commit is contained in:
4
Makefile
4
Makefile
@@ -1,5 +1,5 @@
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -Wextra -g
|
||||
CFLAGS = -Wextra -g
|
||||
LIBS = -lm
|
||||
|
||||
# Get all .c files
|
||||
@@ -19,4 +19,4 @@ $(TARGET): $(OBJECTS)
|
||||
clean:
|
||||
rm -f $(OBJECTS) $(TARGET)
|
||||
|
||||
.PHONY: all clean
|
||||
.PHONY: all clean
|
||||
|
||||
231
builtins.c
231
builtins.c
@@ -36,7 +36,7 @@ char *builtin_str[] = {
|
||||
"bookmark", "bookmarks", "goto", "unbookmark", "focus_timer",
|
||||
"weather", "grep", "grep-text", "ripgrep", "fzf",
|
||||
"clip", "echo", "theme", "loc", "git_status",
|
||||
"gg"};
|
||||
"gg", "ls",};
|
||||
|
||||
// Array of function pointers to built-in command implementations
|
||||
int (*builtin_func[])(char **) = {
|
||||
@@ -47,7 +47,7 @@ int (*builtin_func[])(char **) = {
|
||||
&lsh_bookmark, &lsh_bookmarks, &lsh_goto, &lsh_unbookmark, &lsh_focus_timer,
|
||||
&lsh_weather, &lsh_grep, &lsh_actual_grep, &lsh_ripgrep, &lsh_fzf_native,
|
||||
&lsh_clip, &lsh_echo, &lsh_theme, &lsh_loc, &lsh_git_status,
|
||||
&lsh_gg};
|
||||
&lsh_gg, lsh_dir,};
|
||||
|
||||
/**
|
||||
* Set the console text color
|
||||
@@ -184,142 +184,125 @@ int lsh_exit(char **args) { return 0; }
|
||||
* Lists files in the current directory
|
||||
*/
|
||||
int lsh_dir(char **args) {
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
struct stat file_stat;
|
||||
char cwd[PATH_MAX];
|
||||
char file_path[PATH_MAX];
|
||||
int count = 0;
|
||||
int detailed = 0;
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
struct stat file_stat;
|
||||
char cwd[PATH_MAX];
|
||||
char file_path[PATH_MAX];
|
||||
int detailed = 0;
|
||||
|
||||
// Check if we should show detailed listing
|
||||
if (args[1] != NULL && (strcmp(args[1], "-l") == 0 || strcmp(args[1], "--long") == 0)) {
|
||||
detailed = 1;
|
||||
}
|
||||
// Create table headers
|
||||
char *headers[] = {"Name", "Size", "Type", "Modified"};
|
||||
TableData *table = create_table(headers, 4);
|
||||
if (!table) {
|
||||
fprintf(stderr, "lsh: failed to create table\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (getcwd(cwd, sizeof(cwd)) == NULL) {
|
||||
perror("lsh: getcwd");
|
||||
return 1;
|
||||
}
|
||||
if (getcwd(cwd, sizeof(cwd)) == NULL) {
|
||||
perror("lsh: getcwd");
|
||||
free_table(table);
|
||||
return 1;
|
||||
}
|
||||
|
||||
dir = opendir(cwd);
|
||||
if (dir == NULL) {
|
||||
perror("lsh: opendir");
|
||||
return 1;
|
||||
}
|
||||
dir = opendir(cwd);
|
||||
if (dir == NULL) {
|
||||
perror("lsh: opendir");
|
||||
free_table(table);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (detailed) {
|
||||
printf("Mode Size Modified Name\n");
|
||||
printf("----------------------------------------------------\n");
|
||||
}
|
||||
// Collect all entries
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
// Skip . and .. entries
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// First collect all entries
|
||||
typedef struct {
|
||||
char name[256];
|
||||
struct stat stat;
|
||||
int is_dir;
|
||||
} DirEntry;
|
||||
snprintf(file_path, sizeof(file_path), "%s/%s", cwd, entry->d_name);
|
||||
if (stat(file_path, &file_stat) == 0) {
|
||||
// Create a new row
|
||||
DataValue *row = (DataValue*)malloc(4 * sizeof(DataValue));
|
||||
if (!row) {
|
||||
fprintf(stderr, "lsh: allocation error\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
DirEntry *entries = malloc(1000 * sizeof(DirEntry)); // Arbitrary limit
|
||||
int entry_count = 0;
|
||||
// Name column
|
||||
row[0].type = TYPE_STRING;
|
||||
row[0].value.str_val = strdup(entry->d_name);
|
||||
row[0].is_highlighted = S_ISDIR(file_stat.st_mode); // Highlight directories
|
||||
|
||||
while ((entry = readdir(dir)) != NULL && entry_count < 1000) {
|
||||
// Skip . and .. entries
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
|
||||
continue;
|
||||
}
|
||||
// Size column
|
||||
row[1].type = TYPE_SIZE;
|
||||
row[1].value.str_val = malloc(32);
|
||||
if (S_ISDIR(file_stat.st_mode)) {
|
||||
strcpy(row[1].value.str_val, "<DIR>");
|
||||
} else if (file_stat.st_size < 1024) {
|
||||
snprintf(row[1].value.str_val, 32, "%d B", (int)file_stat.st_size);
|
||||
} else if (file_stat.st_size < 1024 * 1024) {
|
||||
snprintf(row[1].value.str_val, 32, "%.1f KB", file_stat.st_size / 1024.0);
|
||||
} else {
|
||||
snprintf(row[1].value.str_val, 32, "%.1f MB", file_stat.st_size / (1024.0 *
|
||||
1024.0));
|
||||
}
|
||||
row[1].is_highlighted = 0;
|
||||
|
||||
snprintf(file_path, sizeof(file_path), "%s/%s", cwd, entry->d_name);
|
||||
if (stat(file_path, &file_stat) == 0) {
|
||||
strcpy(entries[entry_count].name, entry->d_name);
|
||||
entries[entry_count].stat = file_stat;
|
||||
entries[entry_count].is_dir = S_ISDIR(file_stat.st_mode);
|
||||
entry_count++;
|
||||
}
|
||||
}
|
||||
// Type column
|
||||
row[2].type = TYPE_STRING;
|
||||
if (S_ISDIR(file_stat.st_mode)) {
|
||||
row[2].value.str_val = strdup("Directory");
|
||||
} else if (S_ISREG(file_stat.st_mode)) {
|
||||
// Try to determine file type by extension
|
||||
char *ext = strrchr(entry->d_name, '.');
|
||||
if (ext != NULL) {
|
||||
ext++; // Skip the dot
|
||||
if (strcasecmp(ext, "c") == 0 || strcasecmp(ext, "cpp") == 0 ||
|
||||
strcasecmp(ext, "h") == 0 || strcasecmp(ext, "hpp") == 0) {
|
||||
row[2].value.str_val = strdup("Source");
|
||||
} else if (strcasecmp(ext, "exe") == 0 || strcasecmp(ext, "bat") == 0 ||
|
||||
strcasecmp(ext, "sh") == 0 || strcasecmp(ext, "com") == 0) {
|
||||
row[2].value.str_val = strdup("Executable");
|
||||
} else if (strcasecmp(ext, "txt") == 0 || strcasecmp(ext, "md") == 0 ||
|
||||
strcasecmp(ext, "log") == 0) {
|
||||
row[2].value.str_val = strdup("Text");
|
||||
} else if (strcasecmp(ext, "jpg") == 0 || strcasecmp(ext, "png") == 0 ||
|
||||
strcasecmp(ext, "gif") == 0 || strcasecmp(ext, "bmp") == 0) {
|
||||
row[2].value.str_val = strdup("Image");
|
||||
} else {
|
||||
row[2].value.str_val = strdup("File");
|
||||
}
|
||||
} else {
|
||||
row[2].value.str_val = strdup("File");
|
||||
}
|
||||
} else {
|
||||
row[2].value.str_val = strdup("Special");
|
||||
}
|
||||
row[2].is_highlighted = 0;
|
||||
|
||||
closedir(dir);
|
||||
// Modified date column
|
||||
row[3].type = TYPE_STRING;
|
||||
row[3].value.str_val = malloc(32);
|
||||
struct tm *tm_info = localtime(&file_stat.st_mtime);
|
||||
strftime(row[3].value.str_val, 32, "%Y-%m-%d %H:%M", tm_info);
|
||||
row[3].is_highlighted = 0;
|
||||
|
||||
// Sort entries - directories first then files
|
||||
for (int i = 0; i < entry_count - 1; i++) {
|
||||
for (int j = i + 1; j < entry_count; j++) {
|
||||
if (entries[i].is_dir < entries[j].is_dir ||
|
||||
(entries[i].is_dir == entries[j].is_dir &&
|
||||
strcmp(entries[i].name, entries[j].name) > 0)) {
|
||||
DirEntry temp = entries[i];
|
||||
entries[i] = entries[j];
|
||||
entries[j] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add row to table
|
||||
add_table_row(table, row);
|
||||
}
|
||||
}
|
||||
|
||||
// Display entries
|
||||
for (int i = 0; i < entry_count; i++) {
|
||||
if (detailed) {
|
||||
// Format mode (simplified)
|
||||
char mode[11] = "----------";
|
||||
if (entries[i].is_dir) mode[0] = 'd';
|
||||
if (entries[i].stat.st_mode & S_IRUSR) mode[1] = 'r';
|
||||
if (entries[i].stat.st_mode & S_IWUSR) mode[2] = 'w';
|
||||
if (entries[i].stat.st_mode & S_IXUSR) mode[3] = 'x';
|
||||
if (entries[i].stat.st_mode & S_IRGRP) mode[4] = 'r';
|
||||
if (entries[i].stat.st_mode & S_IWGRP) mode[5] = 'w';
|
||||
if (entries[i].stat.st_mode & S_IXGRP) mode[6] = 'x';
|
||||
if (entries[i].stat.st_mode & S_IROTH) mode[7] = 'r';
|
||||
if (entries[i].stat.st_mode & S_IWOTH) mode[8] = 'w';
|
||||
if (entries[i].stat.st_mode & S_IXOTH) mode[9] = 'x';
|
||||
closedir(dir);
|
||||
|
||||
// Format size
|
||||
char size_str[20];
|
||||
if (entries[i].stat.st_size < 1024) {
|
||||
snprintf(size_str, sizeof(size_str), "%d B", (int)entries[i].stat.st_size);
|
||||
} else if (entries[i].stat.st_size < 1024 * 1024) {
|
||||
snprintf(size_str, sizeof(size_str), "%.1f KB",
|
||||
entries[i].stat.st_size / 1024.0);
|
||||
} else {
|
||||
snprintf(size_str, sizeof(size_str), "%.1f MB",
|
||||
entries[i].stat.st_size / (1024.0 * 1024.0));
|
||||
}
|
||||
// Print the table
|
||||
print_table(table);
|
||||
|
||||
// Format time
|
||||
char time_str[20];
|
||||
struct tm *tm_info = localtime(&entries[i].stat.st_mtime);
|
||||
strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M", tm_info);
|
||||
// Free the table
|
||||
free_table(table);
|
||||
|
||||
// Print entry with colors
|
||||
printf("%s %-10s %-17s ", mode, size_str, time_str);
|
||||
|
||||
if (entries[i].is_dir) {
|
||||
printf(ANSI_COLOR_BLUE "%s" ANSI_COLOR_RESET "\n", entries[i].name);
|
||||
} else if (entries[i].stat.st_mode & S_IXUSR) {
|
||||
printf(ANSI_COLOR_GREEN "%s" ANSI_COLOR_RESET "\n", entries[i].name);
|
||||
} else {
|
||||
printf("%s\n", entries[i].name);
|
||||
}
|
||||
} else {
|
||||
count++;
|
||||
if (entries[i].is_dir) {
|
||||
printf(ANSI_COLOR_BLUE "%-20s" ANSI_COLOR_RESET, entries[i].name);
|
||||
} else if (entries[i].stat.st_mode & S_IXUSR) {
|
||||
printf(ANSI_COLOR_GREEN "%-20s" ANSI_COLOR_RESET, entries[i].name);
|
||||
} else {
|
||||
printf("%-20s", entries[i].name);
|
||||
}
|
||||
|
||||
if (count % 4 == 0) {
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
free(entries);
|
||||
|
||||
if (!detailed && count % 4 != 0) {
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Built-in command: clear
|
||||
@@ -819,4 +802,4 @@ int lsh_gg(char **args) {
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/**
|
||||
* builtins.h
|
||||
* builtins.h
|
||||
* Declarations for all built-in shell commands
|
||||
*/
|
||||
|
||||
@@ -97,4 +97,4 @@ extern int (*builtin_func[])(char **);
|
||||
*/
|
||||
char *extract_json_string(const char *json, const char *key);
|
||||
|
||||
#endif // BUILTINS_H
|
||||
#endif // BUILTINS_H
|
||||
|
||||
BIN
builtins.o
BIN
builtins.o
Binary file not shown.
258
shell.c
258
shell.c
@@ -22,13 +22,15 @@
|
||||
#include <termios.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <signal.h>
|
||||
#include <dirent.h> // For DIR, opendir, readdir
|
||||
#include <sys/stat.h> // For stat
|
||||
|
||||
// Global variables for status bar
|
||||
static int g_console_width = 80;
|
||||
static int g_status_line = 0;
|
||||
static WORD g_normal_attributes = 7; // Default white on black
|
||||
static WORD g_status_attributes = 12; // Red
|
||||
static BOOL g_status_bar_enabled = FALSE; // Flag to track if status bar is enabled
|
||||
static int g_normal_attributes = 7; // Default white on black
|
||||
static int g_status_attributes = 12; // Red
|
||||
static int g_status_bar_enabled = 0; // Flag to track if status bar is enabled
|
||||
static struct termios g_orig_termios; // Original terminal settings
|
||||
|
||||
/**
|
||||
@@ -160,7 +162,7 @@ int init_status_bar(int fd) {
|
||||
|
||||
g_console_width = width;
|
||||
g_status_line = height;
|
||||
g_status_bar_enabled = TRUE;
|
||||
g_status_bar_enabled = 1;
|
||||
|
||||
// Clear status line
|
||||
printf(ANSI_SAVE_CURSOR);
|
||||
@@ -328,6 +330,205 @@ void get_path_display(const char *cwd, char *parent_dir_name,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a TableData structure from an ls command
|
||||
*/
|
||||
TableData* create_ls_table(char **args) {
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
struct stat file_stat;
|
||||
char cwd[PATH_MAX];
|
||||
char file_path[PATH_MAX];
|
||||
|
||||
// Create table headers
|
||||
char *headers[] = {"Name", "Size", "Type", "Modified"};
|
||||
TableData *table = create_table(headers, 4);
|
||||
if (!table) {
|
||||
fprintf(stderr, "lsh: failed to create table\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (getcwd(cwd, sizeof(cwd)) == NULL) {
|
||||
perror("lsh: getcwd");
|
||||
free_table(table);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dir = opendir(cwd);
|
||||
if (dir == NULL) {
|
||||
perror("lsh: opendir");
|
||||
free_table(table);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Collect all entries
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
// Skip . and .. entries
|
||||
if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
snprintf(file_path, sizeof(file_path), "%s/%s", cwd, entry->d_name);
|
||||
if (stat(file_path, &file_stat) == 0) {
|
||||
// Create a new row
|
||||
DataValue *row = (DataValue*)malloc(4 * sizeof(DataValue));
|
||||
if (!row) {
|
||||
fprintf(stderr, "lsh: allocation error\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
// Name column
|
||||
row[0].type = TYPE_STRING;
|
||||
row[0].value.str_val = strdup(entry->d_name);
|
||||
row[0].is_highlighted = S_ISDIR(file_stat.st_mode); // Highlight directories
|
||||
|
||||
// Size column
|
||||
row[1].type = TYPE_SIZE;
|
||||
row[1].value.str_val = malloc(32);
|
||||
if (S_ISDIR(file_stat.st_mode)) {
|
||||
strcpy(row[1].value.str_val, "<DIR>");
|
||||
} else if (file_stat.st_size < 1024) {
|
||||
snprintf(row[1].value.str_val, 32, "%d B", (int)file_stat.st_size);
|
||||
} else if (file_stat.st_size < 1024 * 1024) {
|
||||
snprintf(row[1].value.str_val, 32, "%.1f KB", file_stat.st_size / 1024.0);
|
||||
} else {
|
||||
snprintf(row[1].value.str_val, 32, "%.1f MB", file_stat.st_size / (1024.0 * 1024.0));
|
||||
}
|
||||
row[1].is_highlighted = 0;
|
||||
|
||||
// Type column
|
||||
row[2].type = TYPE_STRING;
|
||||
if (S_ISDIR(file_stat.st_mode)) {
|
||||
row[2].value.str_val = strdup("Directory");
|
||||
} else if (S_ISREG(file_stat.st_mode)) {
|
||||
// Try to determine file type by extension
|
||||
char *ext = strrchr(entry->d_name, '.');
|
||||
if (ext != NULL) {
|
||||
ext++; // Skip the dot
|
||||
if (strcasecmp(ext, "c") == 0 || strcasecmp(ext, "cpp") == 0 ||
|
||||
strcasecmp(ext, "h") == 0 || strcasecmp(ext, "hpp") == 0) {
|
||||
row[2].value.str_val = strdup("Source");
|
||||
} else if (strcasecmp(ext, "exe") == 0 || strcasecmp(ext, "bat") == 0 ||
|
||||
strcasecmp(ext, "sh") == 0 || strcasecmp(ext, "com") == 0) {
|
||||
row[2].value.str_val = strdup("Executable");
|
||||
} else if (strcasecmp(ext, "txt") == 0 || strcasecmp(ext, "md") == 0 ||
|
||||
strcasecmp(ext, "log") == 0) {
|
||||
row[2].value.str_val = strdup("Text");
|
||||
} else if (strcasecmp(ext, "jpg") == 0 || strcasecmp(ext, "png") == 0 ||
|
||||
strcasecmp(ext, "gif") == 0 || strcasecmp(ext, "bmp") == 0) {
|
||||
row[2].value.str_val = strdup("Image");
|
||||
} else {
|
||||
row[2].value.str_val = strdup("File");
|
||||
}
|
||||
} else {
|
||||
row[2].value.str_val = strdup("File");
|
||||
}
|
||||
} else {
|
||||
row[2].value.str_val = strdup("Special");
|
||||
}
|
||||
row[2].is_highlighted = 0;
|
||||
|
||||
// Modified date column
|
||||
row[3].type = TYPE_STRING;
|
||||
row[3].value.str_val = malloc(32);
|
||||
struct tm *tm_info = localtime(&file_stat.st_mtime);
|
||||
strftime(row[3].value.str_val, 32, "%Y-%m-%d %H:%M", tm_info);
|
||||
row[3].is_highlighted = 0;
|
||||
|
||||
// Add row to table
|
||||
add_table_row(table, row);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
return table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse input line into an array of commands (for pipelines)
|
||||
*/
|
||||
char*** lsh_split_commands(char *line) {
|
||||
char ***commands = NULL;
|
||||
char **command = NULL;
|
||||
char *cmd_str, *token, *saveptr1, *saveptr2;
|
||||
int cmd_count = 0, cmd_capacity = 10;
|
||||
int token_count = 0, token_capacity = 10;
|
||||
|
||||
// Allocate initial commands array
|
||||
commands = malloc(cmd_capacity * sizeof(char**));
|
||||
if (!commands) {
|
||||
perror("lsh: allocation error");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Split by pipe symbol '|'
|
||||
cmd_str = strtok_r(line, "|", &saveptr1);
|
||||
while (cmd_str != NULL) {
|
||||
// Trim whitespace
|
||||
while (*cmd_str && isspace(*cmd_str)) cmd_str++;
|
||||
|
||||
// Allocate command token array
|
||||
command = malloc(token_capacity * sizeof(char*));
|
||||
if (!command) {
|
||||
perror("lsh: allocation error");
|
||||
// Free previous allocations
|
||||
for (int i = 0; i < cmd_count; i++) {
|
||||
for (int j = 0; commands[i][j] != NULL; j++) {
|
||||
free(commands[i][j]);
|
||||
}
|
||||
free(commands[i]);
|
||||
}
|
||||
free(commands);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Split command into tokens
|
||||
token_count = 0;
|
||||
token = strtok_r(cmd_str, " \t\r\n\a", &saveptr2);
|
||||
while (token != NULL) {
|
||||
// Check if we need to resize tokens array
|
||||
if (token_count >= token_capacity - 1) {
|
||||
token_capacity *= 2;
|
||||
command = realloc(command, token_capacity * sizeof(char*));
|
||||
if (!command) {
|
||||
perror("lsh: allocation error");
|
||||
// Free previous allocations
|
||||
for (int i = 0; i < cmd_count; i++) {
|
||||
for (int j = 0; commands[i][j] != NULL; j++) {
|
||||
free(commands[i][j]);
|
||||
}
|
||||
free(commands[i]);
|
||||
}
|
||||
free(commands);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
command[token_count] = strdup(token);
|
||||
token_count++;
|
||||
token = strtok_r(NULL, " \t\r\n\a", &saveptr2);
|
||||
}
|
||||
command[token_count] = NULL; // Null-terminate the tokens array
|
||||
|
||||
// Check if we need to resize commands array
|
||||
if (cmd_count >= cmd_capacity - 1) {
|
||||
cmd_capacity *= 2;
|
||||
commands = realloc(commands, cmd_capacity * sizeof(char**));
|
||||
if (!commands) {
|
||||
perror("lsh: allocation error");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
commands[cmd_count] = command;
|
||||
cmd_count++;
|
||||
cmd_str = strtok_r(NULL, "|", &saveptr1);
|
||||
}
|
||||
|
||||
commands[cmd_count] = NULL; // Null-terminate the commands array
|
||||
return commands;
|
||||
}
|
||||
|
||||
/**
|
||||
* Launch an external program
|
||||
*/
|
||||
@@ -402,6 +603,51 @@ int lsh_execute_piped(char ***commands) {
|
||||
return 1; // Nothing to execute
|
||||
}
|
||||
|
||||
// Check if this is a table operation starting with ls/dir
|
||||
if (strcmp(commands[0][0], "ls") == 0 || strcmp(commands[0][0], "dir") == 0) {
|
||||
// Create a table from ls command
|
||||
TableData *table = create_ls_table(commands[0]);
|
||||
if (!table) {
|
||||
return 1; // Error already printed
|
||||
}
|
||||
|
||||
// Apply filters from the pipeline
|
||||
for (int i = 1; commands[i] != NULL; i++) {
|
||||
// Find the filter command
|
||||
char *filter_cmd = commands[i][0];
|
||||
int filter_idx = -1;
|
||||
|
||||
for (int j = 0; j < filter_count; j++) {
|
||||
if (strcmp(filter_cmd, filter_str[j]) == 0) {
|
||||
filter_idx = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (filter_idx == -1) {
|
||||
fprintf(stderr, "lsh: unknown filter command: %s\n", filter_cmd);
|
||||
free_table(table);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Apply the filter
|
||||
TableData *filtered_table = filter_func[filter_idx](table, &commands[i][1]);
|
||||
free_table(table); // Free the old table
|
||||
|
||||
if (!filtered_table) {
|
||||
return 1; // Error already printed
|
||||
}
|
||||
|
||||
table = filtered_table;
|
||||
}
|
||||
|
||||
// Print the final table
|
||||
print_table(table);
|
||||
free_table(table);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (cmd_count == 1) {
|
||||
// No piping needed
|
||||
return lsh_execute(commands[0]);
|
||||
@@ -562,7 +808,7 @@ void lsh_loop(void) {
|
||||
|
||||
// Check for pipes and parse into multiple commands if present
|
||||
if (strchr(line, '|') != NULL) {
|
||||
commands = lsh_split_piped_line(line);
|
||||
commands = lsh_split_commands(line);
|
||||
status = lsh_execute_piped(commands);
|
||||
free_commands(commands);
|
||||
} else {
|
||||
@@ -604,4 +850,4 @@ void lsh_loop(void) {
|
||||
|
||||
// Restore terminal
|
||||
restore_terminal(terminal_fd, &g_orig_termios);
|
||||
}
|
||||
}
|
||||
16
shell.h
16
shell.h
@@ -30,6 +30,22 @@ int lsh_execute(char **args);
|
||||
*/
|
||||
int lsh_execute_piped(char ***commands);
|
||||
|
||||
/**
|
||||
* Create a TableData structure from an ls command
|
||||
*
|
||||
* @param args Command arguments
|
||||
* @return TableData pointer (must be freed by caller) or NULL on error
|
||||
*/
|
||||
TableData* create_ls_table(char **args);
|
||||
|
||||
/**
|
||||
* Parse input line into an array of commands (for pipelines)
|
||||
*
|
||||
* @param line Input command line
|
||||
* @return Null-terminated array of command arrays
|
||||
*/
|
||||
char*** lsh_split_commands(char *line);
|
||||
|
||||
/**
|
||||
* Launch an external program
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user