diff options
Diffstat (limited to '')
-rw-r--r-- | src/commands/cat.c | 51 | ||||
-rw-r--r-- | src/commands/ed.c | 528 | ||||
-rw-r--r-- | src/commands/ls.c | 184 |
3 files changed, 683 insertions, 80 deletions
diff --git a/src/commands/cat.c b/src/commands/cat.c index 8e22706..dd1a732 100644 --- a/src/commands/cat.c +++ b/src/commands/cat.c @@ -2,6 +2,7 @@ #include <ctype.h> #include <errno.h> +#include <stdio.h> #include <string.h> #include <sys/stat.h> @@ -90,18 +91,26 @@ COMMAND(cat) { flags.change_tabs = false; flags.end_lines_dollar = false; + int start = 0; + for (int i = 0; i < argc; i++) { if (!prefix("-", argv[i])) { continue; } + if (streql("-", argv[i])) { + break; + } + if (streql("--help", argv[i])) { help(); } - size_t len = strlen(argv[i] + 1); - for (size_t j = 0; j < len; j++) { - char c = argv[i][j + 1]; + start++; + + size_t len = strlen(argv[i]); + for (size_t j = 1; j < len; j++) { + char c = argv[i][j]; switch (c) { case 'n': flags.number_lines = true; @@ -131,33 +140,19 @@ COMMAND(cat) { } } - bool files = false; - for (int i = 0; i < argc; i++) { - if (streql("-", argv[i])) { - files = true; - cat_file(stdin, flags); - } else if (prefix("-", argv[i])) { - continue; - } else { - files = true; - struct stat s; - if (stat(argv[i], &s) < 0) { - printf("error: failed to read %s: %s\n", argv[i], strerror(errno)); - continue; - } - if (!S_ISREG(s.st_mode)) { - printf("error: %s is not a file\n", argv[i]); - continue; - } - FILE* in = get_file(argv[i], "r"); - cat_file(in, flags); - fclose(in); - } - } + int arg_len = argc - start; - if (!files) { + if (arg_len < 1) { cat_file(stdin, flags); + return EXIT_SUCCESS; } - + + for (int i = start; i < argc; i++) { + FILE* in = get_file(argv[i], "r"); + cat_file(in, flags); + if (in != stdin) + fclose(in); + } + return EXIT_SUCCESS; } diff --git a/src/commands/ed.c b/src/commands/ed.c new file mode 100644 index 0000000..2082ef6 --- /dev/null +++ b/src/commands/ed.c @@ -0,0 +1,528 @@ +#include "../command.h" +#include "../util//regex.h" + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#define INPUT_LEN 1024 + +static char** lines = NULL; +static unsigned long line_capacity; +static unsigned long line_count; +static unsigned long line_current; +static bool pending_writes; + +enum LineAddressType { + INDEX, + RANGE, + SET, +}; + +struct LineAddress { + enum LineAddressType type; + union { + struct { + long int i; + } index; + struct { + long int a; + long int b; + } range; + struct { + long int* b; + unsigned long c; + unsigned long s; + } set; + } data; + bool empty; +}; + +enum RegexDirection { + BEFORE, + AFTER, + ALL +}; + +static bool parse_regex(char** end, struct LineAddress* address, enum RegexDirection dir) { + char c; + char* index = *end; + char* regex_str = index; + while(true) { + c = *(index++); + if (c == '\0') { + fprintf(stderr, "error: missing regex after %c\n", dir == BEFORE ? '?' : '/'); + return false; + } + if (c == (dir == BEFORE ? '?' : '/')) { + *(index - 1) = '\0'; + break; + } + } + unsigned long cap = 8; + unsigned long siz = 0; + long int* buf = malloc(cap * sizeof(unsigned long)); + + re_t regex = re_compile(regex_str); + unsigned long i = (dir == ALL ? 0 : line_current); + unsigned long until = (dir == BEFORE ? 0 : line_count - 1); + for (; (dir == BEFORE ? i >= until : i < until); dir == BEFORE ? i-- : i++) { + int len; + if (re_matchp(regex, lines[i], &len) == -1) { + if (dir == BEFORE && i == 0) break; + continue; + } + if (cap == siz) { + cap *= 2; + buf = realloc(buf, cap * sizeof(unsigned long)); + } + buf[siz] = i; + siz++; + if (dir == BEFORE && i == 0) break; + } + + address->type = SET; + address->data.set.s = siz; + address->data.set.c = cap; + address->data.set.b = buf; + *end = index; + return true; +} + +static bool read_address(char** command, bool whitespace, struct LineAddress* a) { + char* index = *command; + struct LineAddress address; + memset(&address, 0, sizeof(struct LineAddress)); + + address.empty = false; + if (strlen(*command) < 1) { + address.type = INDEX; + address.data.index.i = line_current + 1; + if (line_current >= line_count) line_current = line_count - 1; + *a = address; + return true; + } + + char* end_pre; + long int n_pre = strtol(index, &end_pre, 10) - 1; + if (end_pre == index) { + n_pre = -1; + } else { + if (n_pre < 0) { + fprintf(stderr, "error: input cannot be negative\n"); + return false; + } + index = end_pre; + } + + char pre = *(index++); + switch (pre) { + case '.': + address.type = INDEX; + address.data.index.i = line_current; + break; + case '$': + address.type = INDEX; + address.data.index.i = line_count - 1; + break; + case '-': + case '^': { + address.type = INDEX; + char* end; + long int n = strtol(index, &end, 10) - 1; + if (n < 0) { + fprintf(stderr, "error: input cannot be negative\n"); + return false; + } + if (index == end) { + address.data.index.i = line_current - 1; + } else { + address.data.index.i = line_current - n; + } + if (address.data.index.i < 0) { + fprintf(stderr, "error: line number %ld does not exist\n", address.data.index.i + 1); + return false; + } + break; + } + case '+': { + address.type = INDEX; + char* end; + long int n = strtol(index, &end, 10) - 1; + if (n < 0) { + fprintf(stderr, "error: input cannot be negative\n"); + return false; + } + if (index == end) { + address.data.index.i = line_current + 1; + } else { + address.data.index.i = line_current + n; + } + if (address.data.index.i >= (long int) line_count) { + fprintf(stderr, "error: line number %ld does not exist\n", address.data.index.i + 1); + return false; + } + break; + } + case '%': + address.type = RANGE; + address.data.range.a = 0; + address.data.range.b = line_count - 1; + break; + case ';': + address.type = RANGE; + address.data.range.a = line_current; + address.data.range.b = line_count - 1; + break; + case '/': + if (!parse_regex(&index, &address, AFTER)) return false; + break; + case '?': + if (!parse_regex(&index, &address, BEFORE)) return false; + break; + default: { + index--; + if (n_pre == -1) { + address.type = INDEX; + address.data.index.i = line_current; + address.empty = true; + break; + } else if (whitespace) { + address.type = INDEX; + address.data.index.i = line_current + n_pre; + } else { + address.type = INDEX; + address.data.index.i = n_pre; + } + if (address.data.index.i < 0 || address.data.index.i >= (long int) line_count) { + fprintf(stderr, "error: line number %ld does not exist\n", address.data.index.i + 1); + return false; + } + } + } + *command = index; + *a = address; + return true; +} + +static void free_address (struct LineAddress address) { + if (address.type != SET) return; + free(address.data.set.b); +} + +static void free_data() { + if (lines == NULL) return; + for (unsigned long i = 0; i < line_count; i++) + free(lines[i]); + free(lines); + lines = NULL; +} + +static void load_empty() { + free_data(); + + line_capacity = 8; + lines = malloc(sizeof(char*) * line_capacity); + + line_count = 0; + line_current = 0; + pending_writes = false; +} + +static void get_input(FILE* file, char*** buffer, unsigned long* capacity, unsigned long* size) { + unsigned long cap = 8; + unsigned long siz = 0; + char** buf = malloc(sizeof(char*) * cap); + + char* line = NULL; + size_t offset = 0; + + clearerr(stdin); + while (getline(&line, &offset, file) != -1) { + if (cap == siz) { + cap *= 2; + buf = realloc(buf, sizeof(char*) * cap); + } + buf[siz] = line; + siz++; + line = NULL; + } + + free(line); + + *buffer = buf; + *capacity = cap; + *size = siz; +} + +int ed_getline(char *buf, size_t size) { + size_t i = 0; + int ch; + clearerr(stdin); + while ((ch = getchar()) != EOF) { // Read until EOF ... + if (i + 1 < size) { + buf[i++] = ch; + } + if (ch == '\n') { // ... or end of line + break; + } + } + buf[i] = '\0'; + if (i == 0) { + return EOF; + } + return i; +} + +static void load_file(FILE* file) { + free_data(); + line_current = 0; + get_input(file, &lines, &line_capacity, &line_count); + if (file != stdin) + fclose(file); +} + +static bool check_if_sure() { + if (!pending_writes) { + return true; + } + + printf("Do you really want to quit? "); + fflush(stdout); + + char buf[INPUT_LEN]; + if (ed_getline(buf, INPUT_LEN) == EOF) { + putchar('\n'); + return false; + } + + return prefix("y", buf); +} + +static bool skip_whitespace(char** index) { + char c; + bool w = false; + while (c = **index, c == ' ' || c == '\t') { (*index)++; w = true; } + return w; +} + +static void expand(unsigned long count) { + if (count < line_capacity) return; + line_capacity *= 2; + if (count > line_capacity) line_capacity = count; + lines = realloc(lines, line_capacity * sizeof(char*)); +} + +static void append_lines(unsigned long index, char** new, unsigned long new_len) { + if (new_len < 1) return; + pending_writes = true; + expand(line_count + new_len); + if (index + 1 <= line_count) + memmove(&lines[index+new_len], &lines[index], sizeof(char*) * (line_count - index)); + memcpy(&lines[index], new, sizeof(char*) * new_len); + line_count += new_len; +} + +static void delete_lines(unsigned long a, unsigned long b) { + if (b < a) return; + pending_writes = true; + for (unsigned long i = a; i <= b; i++) { + free(lines[i]); + } + if (b == line_count - 1) { + line_count = a; + return; + } + memmove(&lines[a], &lines[b+1], sizeof(char*) * (line_count - (b + 1))); + line_count -= (b - a) + 1; + line_current = a; + if (line_current >= line_count) line_current = line_count - 1; +} + +static bool handle_append(struct LineAddress* address) { + if (address->type != INDEX) { + fprintf(stderr, "error: append command requires index addressing\n"); + return false; + } + if (line_count == 0) { + address->data.index.i = -1; + } + char** buf; + unsigned long cap, size; + get_input(stdin, &buf, &cap, &size); + if (size > 0) { + append_lines(address->data.index.i + 1, buf, size); + } + line_current += size; + free(buf); + return true; +} + +static bool handle_delete(struct LineAddress* address) { + if (address->empty && address->data.index.i >= (long int) line_count) { + fprintf(stderr, "error: line number %ld does not exist\n", address->data.index.i + 1); + return false; + } + if (address->type == INDEX) { + delete_lines(address->data.index.i, address->data.index.i); + } else if (address->type == RANGE) { + delete_lines(address->data.range.a, address->data.range.b); + } else if (address->type == SET) { + for (unsigned long i = 0; i < address->data.set.s; i++) { + delete_lines(address->data.set.b[i], address->data.set.b[i]); + } + } + return true; +} + +static void prompt() { + printf("%ld: ", line_current + 1); + fflush(stdout); + + char buf[INPUT_LEN]; + if (ed_getline(buf, INPUT_LEN) == EOF) { putchar('\n'); return; } + if (buf[0] == '\0') { putchar('\n'); return; } + + char* index = &buf[0]; + bool whitespace = skip_whitespace(&index); + + struct LineAddress address; + if (!read_address(&index, whitespace, &address)) return; + + char cmd = *(index++); + + if (cmd == ',') { + if (address.type != INDEX) { + fprintf(stderr, "error: comma range addressing requires two index addresses\n"); + free_address(address); + return; + } + struct LineAddress address2; + whitespace = skip_whitespace(&index); + if (!read_address(&index, whitespace, &address2)) { + free_address(address); + return; + } + if (address2.type != INDEX) { + fprintf(stderr, "error: comma range addressing requires two index addresses\n"); + free_address(address); + free_address(address2); + return; + } + address.type = RANGE; + address.data.range.a = address.data.index.i; // cursed + address.data.range.b = address2.data.index.i; + + cmd = *(index++); + } + + if (address.type == RANGE && address.data.range.a > address.data.range.b) { + fprintf(stderr, "error: range addressing must be in ascending order\n"); + free_address(address); + return; + } + + switch (cmd) { + case '\n': + case '\0': + if (address.empty) { + if (line_current == line_count) { + fprintf(stderr, "error: line number %ld does not exist\n", line_current + 1); + break; + } else if (line_current + 1 == line_count) { + fprintf(stderr, "error: line number %ld does not exist\n", line_current + 2); + break; + } else { + line_current++; + } + printf("%s", lines[line_current]); + break; + } + if (address.type == INDEX) { + line_current = address.data.index.i; + } else if (address.type == RANGE) { + line_current = address.data.range.b; + } else if (address.type == SET) { + fprintf(stderr, "error: unexpected range addressing\n"); + break; + } + printf("%s", lines[line_current]); + break; + case 'a': + handle_append(&address); + break; + case 'd': + handle_delete(&address); + break; + case 'c': + if (!handle_delete(&address)) { break; } + address.type = INDEX; + address.data.index.i = line_current - 1; + handle_append(&address); + break; + case 'p': + if (address.empty && address.data.index.i >= (long int) line_count) { + fprintf(stderr, "error: line number %ld does not exist\n", address.data.index.i + 1); + break; + } + if (address.type == INDEX) { + printf("%s", lines[address.data.index.i]); + } else if (address.type == RANGE) { + for (long int i = address.data.range.a; i <= address.data.range.b; i++) { + printf("%s", lines[i]); + } + } else if (address.type == SET) { + for (unsigned long i = 0; i < address.data.set.s; i++) { + printf("%s", lines[address.data.set.b[i]]); + } + } + break; + case 'q': + if(check_if_sure()) { + free_address(address); + free_data(); + exit(EXIT_SUCCESS); + }; + break; + case 'Q': + free_address(address); + free_data(); + exit(EXIT_SUCCESS); + case 'g': + skip_whitespace(&index); + free_address(address); + if (*(index++) != '/') { + fprintf(stderr, "error: unexpected character at start or regex\n"); + break; + } + if (!parse_regex(&index, &address, ALL)) { return; } + for (unsigned long i = 0; i < address.data.set.s; i++) { + printf("%s", lines[address.data.set.b[i]]); + } + break; + default: + fprintf(stderr, "error: unimplemented command\n"); + break; + } + + free_address(address); + +} + +static void prompt_loop() { + while (true) { + prompt(); + } +} + +COMMAND(ed) { + if (argc < 1) { + load_empty(); + prompt_loop(); + } else { + FILE* file = get_file(argv[0], "r"); + load_file(file); + prompt_loop(); + } + return EXIT_SUCCESS; +} diff --git a/src/commands/ls.c b/src/commands/ls.c index b0b00a5..8d64f74 100644 --- a/src/commands/ls.c +++ b/src/commands/ls.c @@ -12,12 +12,14 @@ #include <ftw.h> #include <limits.h> -#define FILE_COLOR "\x1b[0m" -#define DIR_COLOR "\x1b[1;34m" -#define SET_UID_COLOR "\x1b[41m" -#define SET_GID_COLOR "\x1b[43m" -#define EXEC_COLOR "\x1b[1;92m" -#define LINK_COLOR "\x1b[1;96m" +#define FILE_COLOR ANSCII BLACK COLOR +#define DIR_COLOR ANSCII BOLD NEXT NORMAL BLUE COLOR +#define DIR_COLOR_EXEC ANSCII BACKGROUND GREEN NEXT NORMAL BLACK COLOR +#define LINK_COLOR ANSCII BOLD NEXT HIGHLIGHT TURQUOISE COLOR +#define SET_UID_COLOR ANSCII BACKGROUND RED NEXT NORMAL WHITE COLOR +#define SET_GID_COLOR ANSCII BACKGROUND YELLOW NEXT NORMAL BLACK COLOR +#define EXEC_COLOR ANSCII BOLD NEXT NORMAL GREEN COLOR +#define BLK_COLOR ANSCII BOLD NEXT NORMAL YELLOW COLOR struct Flags { bool hidden; @@ -25,17 +27,17 @@ struct Flags { bool more_info; bool one_column; bool recurse; - bool colored; + enum When colored; }; struct FileInfo { - char mode[11]; - int links; struct passwd* usr; struct group* grp; - char size[5]; - char date[13]; char name[PATH_MAX]; + char date[13]; + char mode[11]; + char size[5]; + int links; bool set_uid; bool set_gid; bool exec; @@ -76,34 +78,59 @@ static void append_path(char buf[PATH_MAX], const char* dir_path, const char* fi buf[dir_len + file_len] = '\0'; } -static bool get_file_info(struct dirent* file, const char* dir_path, struct FileInfo* info) { +static bool get_file_info(const char* file_path, const char* dir_path, struct FileInfo* info) { uid_t uid = getuid(); gid_t gid = getgid(); char buf[PATH_MAX]; - append_path(buf, dir_path, file->d_name); + append_path(buf, dir_path, file_path); struct stat s; memset(&s, 0, sizeof(struct stat)); - if (stat(buf, &s) < 0) { - // printf("\x1b[0merror: failed to read file '%s': %s\n", buf, strerror(errno)); + if (lstat(buf, &s) < 0) { + printf("\x1b[0merror: failed to read file '%s': %s\n", buf, strerror(errno)); return false; } - + + int ty = (s.st_mode & S_IFMT) >> 12; + info->set_uid = false; info->set_gid = false; info->exec = false; info->name[0] = '\0'; - if (file->d_type == DT_DIR) - info->mode[0] = 'd'; - else if (file->d_type == DT_LNK) - info->mode[0] = 'l'; - else - info->mode[0] = '-'; - + switch (ty) { + case DT_BLK: + info->mode[0] = 'b'; + break; + case DT_CHR: + info->mode[0] = 'c'; + break; + case DT_DIR: + info->mode[0] = 'd'; + break; + case DT_FIFO: + info->mode[0] = 'f'; + break; + case DT_LNK: + info->mode[0] = 'l'; + break; + case DT_SOCK: + info->mode[0] = 's'; + break; + case DT_UNKNOWN: + info->mode[0] = 'u'; + break; + case DT_WHT: + info->mode[0] = 'w'; + break; + default: + info->mode[0] = '-'; + break; + } + info->mode[1] = (s.st_mode & S_IRUSR) ? 'r' : '-'; info->mode[2] = (s.st_mode & S_IWUSR) ? 'w' : '-'; if (s.st_mode & S_IXUSR) { @@ -146,21 +173,31 @@ static bool get_file_info(struct dirent* file, const char* dir_path, struct File info->usr = getpwuid(s.st_uid); info->grp = getgrgid(s.st_gid); info->links = s.st_nlink; - info->type = file->d_type; + info->type = ty; - strcpy(info->name, file->d_name); + strcpy(info->name, file_path); print_file_size(s.st_size, info->size); - print_date_time(s.st_mtim.tv_sec + s.st_mtim.tv_nsec / 1000000, info->date); + print_date_time(s.st_mtim.tv_sec + s.st_mtim.tv_nsec / 1000000000, info->date); return true; } static char* get_file_color(struct FileInfo* info) { char* color; if (info->type == DT_DIR) { - color = DIR_COLOR; + if (info->mode[8] == 'w') { + color = DIR_COLOR_EXEC; + } else { + color = DIR_COLOR; + } } else if (info->type == DT_LNK) { color = LINK_COLOR; + } else if ( + info->type == DT_CHR || + info->type == DT_BLK || + info->type == DT_SOCK + ) { + color = BLK_COLOR; } else { if (info->set_uid) { color = SET_UID_COLOR; @@ -181,7 +218,8 @@ static void list_files(struct FileInfo* files, int file_len, struct FileListInfo if (!isatty(1)) { flags->one_column = true; - flags->colored = false; + if (flags->colored == AUTO) + flags->colored = NO; } char* color; @@ -192,7 +230,7 @@ static void list_files(struct FileInfo* files, int file_len, struct FileListInfo struct FileInfo finfo = files[i]; color = get_file_color(&finfo); if (flags->more_info) { - printf("%s %*d %*s %*s %*s %s %s%s\x1b[0m", + printf("%s %*d %*s %*s %*s %s %s%s%s", finfo.mode, info.max_link, finfo.links, @@ -203,37 +241,40 @@ static void list_files(struct FileInfo* files, int file_len, struct FileListInfo info.max_size, finfo.size, finfo.date, - flags->colored ? color : FILE_COLOR, - finfo.name + flags->colored != NO ? color : "", + finfo.name, + flags->colored != NO ? "\x1b[0m" : "" ); if (finfo.type == DT_LNK) { char path[PATH_MAX]; append_path(path, dir_path, finfo.name); char lnk[PATH_MAX]; - if (readlink(path, lnk, PATH_MAX) < 0) { - putchar('\n'); + ssize_t n; + if ((n = readlink(path, lnk, PATH_MAX)) != -1) { + printf(" -> %.*s\n", (int)n, lnk); } else { - printf(" -> %s\n", lnk); + putchar('\n'); } } else { putchar('\n'); } } else if (flags->one_column) { - printf("%s%s\x1b[0m\n", color, finfo.name); + printf("%s%s%s\n", color, finfo.name, flags->colored != NO ? "\x1b[0m" : ""); } else { if (info.total_len > w.ws_col) { if (i != 0 && i % row_count == 0) putchar('\n'); - printf("%s%*s\x1b[0m", flags->colored ? color : FILE_COLOR, -column_width, finfo.name); + printf("%s%*s%s", flags->colored != NO ? color : "", -column_width, + finfo.name, flags->colored != NO ? "\x1b[0m" : ""); } else { - printf("%s%s\x1b[0m ", flags->colored ? color : FILE_COLOR, finfo.name); + printf("%s%s%s ", flags->colored != NO ? color : "", finfo.name, + flags->colored != NO ? "\x1b[0m" : ""); } } } - if (info.total_len <= w.ws_col) printf("\n"); - + if (!flags->more_info) printf("\n"); } static bool is_dot_dir(const char* path) { @@ -254,25 +295,24 @@ static void push_file( struct FileInfo** files, struct FileListInfo* info, int* size, int* capacity, - struct dirent* file, + const char* file_path, const char* dir_path ) { struct FileInfo finfo; - if (!get_file_info(file, dir_path, &finfo)) return; + if (!get_file_info(file_path, dir_path, &finfo)) return; if (*size == *capacity) { *capacity *= 2; *files = realloc(*files, sizeof(struct FileInfo) * *capacity); } - int user_len = strlen(finfo.usr->pw_name); if (user_len > info->max_usr) info->max_usr = user_len; int group_len = strlen(finfo.grp->gr_name); if (group_len > info->max_grp) info->max_grp = group_len; - int name_len = strlen(file->d_name); + int name_len = strlen(file_path); if (name_len > info->max_name) info->max_name = name_len; int size_len = strlen(finfo.size); @@ -307,10 +347,13 @@ static bool recurse_directory(char* path, struct Flags* flags) { if (!flags->hidden && prefix(".", file->d_name)) continue; if (is_dot_dir(file->d_name)) continue; if (first) { - printf("\n%s%s:%s\n", DIR_COLOR, path, FILE_COLOR); + if (flags->colored == NO) + printf("\n%s:\n", path); + else + printf("\n%s%s:%s\n", DIR_COLOR, path, FILE_COLOR); first = false; } - push_file(&files, &info, &size, &capacity, file, path); + push_file(&files, &info, &size, &capacity, file->d_name, path); } list_files(files, size, info, flags, path); @@ -355,16 +398,39 @@ static bool list_directory(char* path, struct Flags* flags) { while ((file = readdir(d)) != NULL) { if (!flags->hidden && prefix(".", file->d_name)) continue; if (flags->hide_dot && is_dot_dir(file->d_name)) continue; - push_file(&files, &info, &size, &capacity, file, path); + push_file(&files, &info, &size, &capacity, file->d_name, path); } - list_files(files, size, info, flags, path); + if (size > 0) list_files(files, size, info, flags, path); free(files); closedir(d); return true; } +static bool is_dir(const char* path) { + struct stat s; + if (stat(path, &s) < 0) return false; + return S_ISDIR(s.st_mode); +} + +static void list_file_args(int start, int argc, char** argv, struct Flags* flags) { + int capacity = 8; + int size = 0; + struct FileInfo* files = malloc(sizeof(struct FileInfo) * capacity); + struct FileListInfo info; + memset(&info, 0, sizeof(struct FileListInfo)); + + for (int i = start; i < argc; i++) { + if (is_dir(argv[i])) continue; + push_file((struct FileInfo**) &files, &info, &size, &capacity, argv[i], "."); + } + + if (size > 0) list_files(files, size, info, flags, "."); + + free(files); +} + static void help() { printf("Usage: ls [FILE]...\n\n"); printf("List directory contents\n\n"); @@ -384,15 +450,24 @@ COMMAND(ls) { flags.hide_dot = false; flags.one_column = false; flags.recurse = false; - flags.colored = false; + flags.colored = AUTO; int start = 0; for (int i = 0; i < argc; i++) { if (!prefix("-", argv[i])) break; if (streql("--help", argv[i])) help(); start++; - if (streql("--color=auto", argv[i]) || streql("--color=yes", argv[i])) { - flags.colored = true; + if (prefix("--color=", argv[i])) { + char* arg = argv[i] + 8; + if (streql("yes", arg) || streql("always", arg)) { + flags.colored = YES; + } else if (streql("auto", arg)) { + flags.colored = AUTO; + } else if (streql("no", arg) || streql("never", arg)) { + flags.colored = NO; + } else { + error("error: invalid color options: %s", arg); + } continue; } for (size_t j = 1; j < strlen(argv[i]); j++) { @@ -422,14 +497,19 @@ COMMAND(ls) { if (argc - start == 0) { list_directory(".", &flags); - if (!flags.more_info) printf("\n"); return EXIT_SUCCESS; } + list_file_args(start, argc, argv, &flags); + bool titled = argc - start > 1; for (int i = start; i < argc; i++) { + if (!is_dir(argv[i])) continue; if (titled && !flags.recurse) { - printf("\n%s%s:%s\n", DIR_COLOR, argv[i], FILE_COLOR); + if (flags.colored != NO) + printf("\n%s%s:%s\n", DIR_COLOR, argv[i], FILE_COLOR); + else + printf("\n%s:\n", argv[i]); } if (list_directory(argv[i], &flags) && i + 1 != argc) if (titled && !flags.recurse) printf("\n"); |