diff options
Diffstat (limited to 'src/commands')
-rw-r--r-- | src/commands/cat.c | 140 | ||||
-rw-r--r-- | src/commands/cp.c | 240 | ||||
-rw-r--r-- | src/commands/dd.c | 60 | ||||
-rw-r--r-- | src/commands/echo.c | 104 | ||||
-rw-r--r-- | src/commands/ed.c | 917 | ||||
-rw-r--r-- | src/commands/grep.c | 265 | ||||
-rw-r--r-- | src/commands/groups.c | 42 | ||||
-rw-r--r-- | src/commands/head.c | 138 | ||||
-rw-r--r-- | src/commands/id.c | 53 | ||||
-rw-r--r-- | src/commands/ls.c | 552 | ||||
-rw-r--r-- | src/commands/mkdir.c | 65 | ||||
-rw-r--r-- | src/commands/mv.c | 116 | ||||
-rw-r--r-- | src/commands/printf.c | 141 | ||||
-rw-r--r-- | src/commands/rm.c | 136 | ||||
-rw-r--r-- | src/commands/tac.c | 117 | ||||
-rw-r--r-- | src/commands/tail.c | 238 | ||||
-rw-r--r-- | src/commands/tee.c | 81 | ||||
-rw-r--r-- | src/commands/wc.c | 159 | ||||
-rw-r--r-- | src/commands/whoami.c | 27 | ||||
-rw-r--r-- | src/commands/xargs.c | 187 | ||||
-rw-r--r-- | src/commands/yes.c | 26 |
21 files changed, 0 insertions, 3804 deletions
diff --git a/src/commands/cat.c b/src/commands/cat.c deleted file mode 100644 index 0495fe3..0000000 --- a/src/commands/cat.c +++ /dev/null @@ -1,140 +0,0 @@ -#include "../command.h" - -#include <ctype.h> - -static struct { - bool number_lines; - bool number_non_empty; - bool change_non_print; - bool change_tabs; - bool end_lines_dollar; -} flags; - -static bool printable(char c) { - switch (c) { - case '\n': return true; - case '\r': return true; - case '\b': return true; - case '\t': return true; - default: return isprint(c) == 0; - } -} - -static void help(void) { - printf("Usage: cat [-nbvteA] [FILE]...\n\n"); - printf("Print FILEs to stdout\n\n"); - printf("\t-n Number output lines\n"); - printf("\t-b Number nonempty lines\n"); - printf("\t-v Show nonprinting characters as ^x or M-x\n"); - printf("\t-t ...and tabs as ^I\n"); - printf("\t-e ...and end lines with $\n"); - printf("\t-A Same as -vte\n"); -} - -static void cat_file(FILE* file) { - char c; - size_t read; - - size_t line = 1; - bool empty = true; - bool newline = true; - - while ((read = fread(&c, 1, 1, file)) != 0) { - if (c == '\n') { - if (empty && flags.number_lines) { - printf("\t%ld ", line); - } - if (flags.end_lines_dollar) { - printf("$"); - } - line++; - newline = true; - empty = true; - goto print; - } else { - empty = false; - } - - if (!newline) { - goto print; - } - - if (!empty && (flags.number_non_empty || flags.number_lines)) { - printf("\t%ld ", line); - newline = false; - } - print: - if (!flags.change_non_print || printable(c)) { - if (flags.change_tabs && c == '\t') { - fwrite("^I", 1, 2, stdout); - } else { - fwrite(&c, 1, 1, stdout); - } - } else { - c |= '@'; - fwrite(&c, 1, 1, stdout); - } - } -} - -static int short_arg(char c, char* next) { - UNUSED(next); - switch (c) { - case 'n': - flags.number_lines = true; - break; - case 'b': - flags.number_non_empty = true; - break; - case 'v': - flags.change_non_print = true; - break; - case 't': - flags.change_non_print = true; - flags.change_tabs = true; - break; - case 'e': - flags.change_non_print = true; - flags.end_lines_dollar = true; - break; - case 'A': - flags.change_non_print = true; - flags.change_tabs = true; - flags.end_lines_dollar = true; - break; - default: - return ARG_INVALID; - } - return ARG_UNUSED; -} - -COMMAND(cat) { - - int start; - int arg_len; - int i; - - flags.number_lines = false; - flags.number_non_empty = false; - flags.change_non_print = false; - flags.change_tabs = false; - flags.end_lines_dollar = false; - - start = parse_args(argc, argv, help, short_arg, NULL); - - arg_len = argc - start; - - if (arg_len < 1) { - cat_file(stdin); - return EXIT_SUCCESS; - } - - for (i = start; i < argc; i++) { - FILE* in = get_file(argv[i], "r"); - cat_file(in); - if (in != stdin) - fclose(in); - } - - return EXIT_SUCCESS; -} diff --git a/src/commands/cp.c b/src/commands/cp.c deleted file mode 100644 index df88155..0000000 --- a/src/commands/cp.c +++ /dev/null @@ -1,240 +0,0 @@ -#include "../command.h" -#include <dirent.h> -#include <limits.h> -#include <stdio.h> -#include <sys/stat.h> -#include <unistd.h> - -static struct { - bool recurse; - bool preserve; - bool sym_link; - bool hard_link; - bool verbose; -} flags; - -static void help(void) { - printf("Usage: cp [-rplsv] SOURCE... DEST\n\n"); - printf("Copy SOURCEs to DEST\n\n"); - printf("\t-R,-r\tRecurse\n"); - printf("\t-p\tPreserve file attributes if possible\n"); - printf("\t-l,-s\tCreate (sym)links\n"); - printf("\t-v\tVerbose\n"); -} - -static int short_arg(char c, char* next) { - UNUSED(next); - switch (c) { - case 'R': - case 'r': - flags.recurse = true; - break; - case 'p': - flags.preserve = true; - break; - case 'l': - flags.hard_link = true; - flags.sym_link = false; - break; - case 's': - flags.sym_link = true; - flags.hard_link = false; - break; - case 'v': - flags.verbose = true; - break; - default: - return ARG_INVALID; - } - return ARG_UNUSED; -} - -static bool copy_file(char* from, char* to) { - #define BS 1024 - - FILE *from_f, *to_f; - char buf[BS]; - int read; - - from_f = get_file_s(from, "r"); - if (from_f == NULL) { return false; } - - to_f = get_file_s(to, "w"); - if (to_f == NULL) { fclose(from_f); return false; } - - - while ((read = fread(buf, 1, BS, from_f)) > 0) { - fwrite(buf, 1, read, to_f); - } - - if (flags.verbose) { - output("copied '%s'", from); - } - - return true; -} - -static bool symlink_file(char* from, char* to) { - if (symlink(from, to) < 0) { - error_s("failed to symlink '%s': %s", from, strerror(errno)); - return false; - } else if (flags.verbose) { - output("symlinked '%s'", from); - } - return true; -} - -static bool hardlink_file(char* from, char* to) { - if (link(from, to) < 0) { - error_s("failed to hardlink '%s': %s", from, strerror(errno)); - return false; - } else if (flags.verbose) { - output("hardlinked '%s'", from); - } - return true; -} - -static void run_copy(struct stat* s) { - - char* from = get_path_buffer(); - char* to = get_path_buffer_2(); - - bool result; - if (flags.sym_link) { - result = symlink_file(from, to); - } else if (flags.hard_link) { - result = hardlink_file(from, to); - } else { - result = copy_file(from, to); - } - - if (!result) return; - if (!flags.preserve) return; - - if (chmod(to, s->st_mode) < 0) { - error_s("cannot chmod '%s': %s", to, strerror(errno)); - return; - } - - if (chown(to, s->st_uid, s->st_gid) < 0) { - error_s("cannot chown '%s': %s", to, strerror(errno)); - return; - } -} - -static void cp_file(char* path); - -static void cp_directory(struct stat* s) { - - DIR* d; - struct dirent* file; - - if (!flags.recurse) { - error_s("-r not specified; omitting directory '%s'", get_path_buffer()); - return; - } - - if (mkdir(get_path_buffer_2(), s->st_mode) < 0 && errno != EEXIST) { - error_s("cannot create directory '%s': %s", get_path_buffer_2(), strerror(errno)); - return; - } - - d = opendir(get_path_buffer()); - - if (d == NULL) { - error_s("cannot open directory '%s': %s", get_path_buffer(), strerror(errno)); - return; - } - - while ((file = readdir(d)) != NULL) { - if (is_dot_dir(file->d_name)) continue; - cp_file(file->d_name); - } -} - -static char* get_file_name(char* path) { - int last = 0; - int i = 0; - - if (path[0] == '\0') return path; - - while (true) { - if (path[i+1] == '\0') break; - if (path[i] == '/') { - last = i; - } - i++; - } - - if (last == 0) return path; - else return path + last + 1; -} - -static void cp_file(char* path) { - - int save = push_path_buffer(path); - int save2 = push_path_buffer_2(get_file_name(path)); - - struct stat s; - if (lstat(get_path_buffer(), &s) < 0) { - pop_path_buffer(save); - error_s("cannot stat '%s': %s", get_path_buffer(), strerror(errno)); - return; - } - - if (S_ISDIR(s.st_mode)) { - cp_directory(&s); - } else { - run_copy(&s); - } - - pop_path_buffer(save); - pop_path_buffer_2(save2); -} - -COMMAND(cp) { - - int start, i; - struct stat s; - - flags.hard_link = false; - flags.sym_link = false; - flags.preserve = false; - flags.recurse = false; - flags.verbose = false; - - start = parse_args(argc, argv, help, short_arg, NULL); - - if (argc - start < 2) { - global_help(help); - } - - /* only when 2 args and first is a file, the 2nd will be a file */ - if (argc - start == 2) { - struct stat s; - if (lstat(argv[start], &s) < 0) { - error("cannot stat '%s': %s", argv[start], strerror(errno)); - } - push_path_buffer(argv[argc-2]); - push_path_buffer_2(argv[argc-1]); - if (!S_ISDIR(s.st_mode)) { - run_copy(&s); - } else { - cp_directory(&s); - } - return EXIT_SUCCESS; - } - - /* push directory */ - push_path_buffer_2(argv[argc-1]); - - if (lstat(get_path_buffer_2(), &s) < 0) { - error("target: '%s': %s", get_path_buffer_2(), strerror(errno)); - } - - for (i = start; i < argc - 1; i++) { - cp_file(argv[i]); - } - - return EXIT_SUCCESS; -} diff --git a/src/commands/dd.c b/src/commands/dd.c deleted file mode 100644 index 1387317..0000000 --- a/src/commands/dd.c +++ /dev/null @@ -1,60 +0,0 @@ -#include "../command.h" - -static void help(void) { - printf("Usage: dd [if=FILE] [of=FILE] [bs=N] [count=N]\n\n"); - printf("Copy a file with converting and formatting\n\n"); - printf("\tif=FILE\t\tRead from FILE instead of stdin\n"); - printf("\tof=FILE\t\tWrite to FILE instead of stdout\n"); - printf("\tbs=N\t\tRead and write N bytes at a time\n"); - printf("\tcount=N\t\tCopy only N input blocks\n"); -} - -COMMAND(dd) { - - FILE* in_file = stdin; - FILE* out_file = stdout; - int bs = 1024; - int count = -1; - int i; - char* buffer; - size_t read; - - parse_help(argc, argv, help); - - for (i = 0; i < argc; i++) { - if (prefix("if=", argv[i])) { - char* path = argv[i] + 3; - in_file = get_file(path, "rb"); - } else if (prefix("of=", argv[i])) { - char* path = argv[i] + 3; - out_file = get_file(path, "wb"); - } else if (prefix("bs=", argv[i])) { - char* str = argv[i] + 3; - bs = get_number(str); - if (bs < 1) { - error("block size must be greater than 0"); - } - } else if (prefix("count=", argv[i])) { - char* str = argv[i] + 6; - count = get_number(str); - if (count < 1) { - error("count must be greather than 0"); - } - } else { - error("unkown option %s", argv[i]); - } - } - - buffer = malloc(bs); - - while ((read = fread(buffer, 1, bs, in_file)) != 0) { - fwrite(buffer, 1, read, out_file); - if (--count, count == 0) break; - } - - free(buffer); - fclose(in_file); - fclose(out_file); - - return EXIT_SUCCESS; -} diff --git a/src/commands/echo.c b/src/commands/echo.c deleted file mode 100644 index fe70a6a..0000000 --- a/src/commands/echo.c +++ /dev/null @@ -1,104 +0,0 @@ -#include "../command.h" - -static struct { - bool escape_codes; - bool newline; -} flags; - -static void print_with_escape_codes(const char* str) { - - size_t index = 0; - char n; - - while (true) { - char c = str[index]; - index++; - - if (c == '\0') break; - if (c != '\\') { - putchar(c); - continue; - } - - n = str[index]; - index++; - - switch (n) { - case '\\': - putchar('\\'); - break; - case 'b': - putchar('\b'); - break; - case 'c': - exit(EXIT_SUCCESS); - case 'n': - putchar('\n'); - break; - case 'r': - putchar('\r'); - break; - case 't': - putchar('\t'); - break; - case 'v': - putchar('\v'); - break; - default: - putchar(c); - putchar(n); - } - } -} - -static int short_arg(char c, char* next) { - UNUSED(next); - switch (c) { - case 'e': - flags.escape_codes = true; - break; - case 'E': - flags.escape_codes = false; - break; - case 'n': - flags.newline = false; - break; - default: - flags.newline = true; - flags.escape_codes = false; - return ARG_IGNORE; - }; - return ARG_UNUSED; -} - -COMMAND(echo) { - - int start, i; - - if (argc < 1) { - return EXIT_SUCCESS; - } - - flags.escape_codes = false; - flags.newline = true; - - start = parse_args(argc, argv, NULL, short_arg, NULL); - - for (i = start; i < argc; i++) { - if (flags.escape_codes) { - print_with_escape_codes(argv[i]); - } else { - printf("%s", argv[i]); - } - - if (i + 1 != argc) { - putchar(' '); - } - } - - if (flags.newline) { - putchar('\n'); - } - - return EXIT_SUCCESS; -} diff --git a/src/commands/ed.c b/src/commands/ed.c deleted file mode 100644 index d7e8881..0000000 --- a/src/commands/ed.c +++ /dev/null @@ -1,917 +0,0 @@ -#include "../command.h" -#include "../util//regex.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; -static char* default_filename = NULL; -static re_t last_regex = NULL; - -enum LineAddressType { - INDEX, - RANGE, - SET, - FREE -}; - -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 read_regex(char** end, re_t* regex, enum RegexDirection dir) { - char c; - char* index = *end; - char* regex_str = index; - while(true) { - c = *(index++); - if (c == '\0') { - error_s("missing regex after %c\n", dir == BEFORE ? '?' : '/'); - return false; - } - if (c == (dir == BEFORE ? '?' : '/')) { - *(index - 1) = '\0'; - break; - } - } - *regex = re_compile(regex_str); - last_regex = *regex; - *end = index; - return true; -} - -static bool parse_regex(char** end, struct LineAddress* address, enum RegexDirection dir) { - re_t regex; - unsigned long cap, siz, i, until; - long int* buf; - - if (!read_regex(end, ®ex, dir)) return false; - - cap = 8; - siz = 0; - buf = malloc(cap * sizeof(long int)); - - i = (dir == ALL ? 0 : line_current); - 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(long int)); - } - buf[siz] = i; - siz++; - if (dir == BEFORE && i == 0) break; - } - - address->empty = false; - address->type = SET; - address->data.set.s = siz; - address->data.set.c = cap; - address->data.set.b = buf; - return true; -} - -static void free_address (struct LineAddress address) { - if (address.type != SET) return; - address.type = FREE; - free(address.data.set.b); -} - -static void expand_buffer(long int** buf, unsigned long* cap, unsigned long* size) { - if (*cap == *size) { - *cap *= 2; - *buf = realloc(*buf, sizeof(long int) * *cap); - } -} - -static bool parse_regex_lines(char** end, struct LineAddress* address) { - re_t regex; - unsigned long cap, siz; - long int* buf; - int len; - struct LineAddress addr; - - if (!read_regex(end, ®ex, ALL)) return false; - - cap = 8; - siz = 0; - buf = malloc(cap * sizeof(long int)); - - addr = *address; - if (addr.type == INDEX) { - if (re_matchp(regex, lines[addr.data.index.i], &len) != -1) { - buf[0] = addr.data.index.i; - siz = 1; - } - } else if (addr.type == RANGE) { - long int i; - for (i = addr.data.range.a; i < addr.data.range.b; i++) { - if (re_matchp(regex, lines[i], &len) == -1) continue; - expand_buffer(&buf, &cap, &siz); - buf[siz] = i; - siz++; - } - } else if (addr.type == SET) { - unsigned long i; - for (i = 0; i < addr.data.set.s; i++) { - if (re_matchp(regex, lines[addr.data.set.b[i]], &len) == -1) continue; - expand_buffer(&buf, &cap, &siz); - buf[siz] = addr.data.set.b[i]; - siz++; - } - } - - free_address(*address); - address->empty = false; - address->type = SET; - address->data.set.s = siz; - address->data.set.c = cap; - address->data.set.b = buf; - return true; -} - -static bool read_address(char** command, bool whitespace, struct LineAddress* a) { - char* index = *command; - struct LineAddress address; - - char* end_pre; - long int n_pre; - char pre; - - 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; - } - - n_pre = strtol(index, &end_pre, 10) - 1; - if (end_pre == index) { - n_pre = -1; - } else { - if (n_pre < 0) { - error_s("input cannot be negative\n"); - return false; - } - index = end_pre; - } - - 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 '^': { - char* end; - long int n; - - address.type = INDEX; - n = strtol(index, &end, 10) - 1; - - if (n < 0) { - error_s("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) { - error_s("line number %ld does not exist\n", address.data.index.i + 1); - return false; - } - - break; - } - case '+': { - char* end; - long int n; - - address.type = INDEX; - n = strtol(index, &end, 10) - 1; - - if (n < 0) { - error_s("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) { - error_s("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) { - error_s("line number %ld does not exist\n", address.data.index.i + 1); - return false; - } - } - } - *command = index; - *a = address; - return true; -} - -static void free_data(bool all) { - if (lines != NULL) { - unsigned long i; - for (i = 0; i < line_count; i++) { - free(lines[i]); - } - free(lines); - lines = NULL; - } - if (all && default_filename != NULL) { - free(default_filename); - default_filename = NULL; - } -} - -static void load_empty(void) { - free_data(false); - - 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(false); - line_current = 0; - get_input(file, &lines, &line_capacity, &line_count); - if (file != stdin) - fclose(file); - -} - -static bool check_if_sure(char* prompt) { - char buf[INPUT_LEN]; - - if (!pending_writes) { - return true; - } - - printf("%s", prompt); - fflush(stdout); - - 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) { - unsigned long i; - - if (b < a) return; - pending_writes = true; - - for (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) { - char** buf; - unsigned long cap, size; - - if (address->type != INDEX) { - error_s("append command requires index addressing\n"); - return false; - } - - if (line_count == 0) { - address->data.index.i = -1; - } - - get_input(stdin, &buf, &cap, &size); - - if (size > 0) { - append_lines(address->data.index.i + 1, buf, size); - printf("ed: appened %lu lines\n", 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) { - error_s("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); - output("deleted line %ld\n", address->data.index.i+1); - } else if (address->type == RANGE) { - delete_lines(address->data.range.a, address->data.range.b); - output("deleted lines %ld-%ld\n", address->data.range.a+1, address->data.range.b+1); - } else if (address->type == SET) { - unsigned long i; - for (i = 0; i < address->data.set.s; i++) { - delete_lines(address->data.set.b[i], address->data.set.b[i]); - } - output("deleted %lu lines\n", address->data.set.s); - } - - return true; -} - -static bool get_file_name(char** filename) { - size_t len = strlen(*filename); - - if (len < 1 || (len == 1 && **filename == '\n')) { - if (default_filename == NULL) { - error_s("no default filename specified\n"); - return false; - } - *filename = default_filename; - } else { - if ((*filename)[len - 1] == '\n') { - (*filename)[len - 1] = '\0'; - len--; - } - if (default_filename != NULL) { - default_filename = realloc(default_filename, len + 1); - } else { - default_filename = malloc(len + 1); - } - memcpy(default_filename, *filename, len + 1); - *filename = default_filename; - } - return true; -} - -static void write_file(char* filename, struct LineAddress* address, char* type) { - FILE* file; - int wrote; - - if (line_count < 1) { - error_s("cannot write empty file\n"); - return; - } - - if (!get_file_name(&filename)) return; - file = get_file_s(filename, type); - if (file == NULL) return; - - wrote = 0; - - if (address->empty) { - unsigned long i; - for (i = 0; i < line_count; i++) { - fprintf(file, "%s", lines[i]); - wrote++; - } - } else if (address->type == INDEX) { - long int i = address->data.index.i; - fprintf(file, "%s", lines[i]); - wrote++; - } else if (address->type == RANGE) { - long int i; - for (i = address->data.range.a; i < address->data.range.b; i++) { - fprintf(file, "%s", lines[i]); - wrote++; - } - } else if (address->type == SET) { - unsigned long i; - for (i = 0; i < address->data.set.s; i++) { - fprintf(file, "%s", lines[address->data.set.b[i]]); - wrote++; - } - } - - pending_writes = false; - fclose(file); - output("wrote %d lines from %s\n", wrote, filename); -} - -static void read_file(char* filename) { - FILE* file; - char** buf; - long int line; - unsigned long capacity, size; - - if (!get_file_name(&filename)) return; - file = get_file_s(filename, "r"); - if (file == NULL) return; - - capacity = 8; - size = 0; - buf = malloc(capacity * sizeof(char*)); - get_input(file, &buf, &capacity, &size); - - if (size < 1) { - free(buf); - error_s("attempted to read a empty file\n"); - return; - } - - line = -1; - if (line_count > 0) { - line = line_count - 1; - } - - append_lines(line, buf, size); - free(buf); - output("read and appended %lu lines from %s\n", size, filename); -} - -static void expand_string(char** buf, int* capacity, int* size, char* text, int len) { - if (*size + len >= *capacity) { - *capacity *= 2; - if (*capacity < *size + len) *capacity = *size + len; - *buf = realloc(*buf, *capacity); - } - memcpy(*buf + *size, text, len); - *size += len; -} - -static int substute_string(long int index, long int matches, re_t regex, char* sub, int sub_len) { - int capacity = 8; - int size = 0; - char* buf = malloc(sizeof(char) * capacity); - long int left; - - int offset = 0; - int matches_found = 0; - while(true) { - int distance, len; - - if (lines[index][offset] == '\0') break; - - if (matches_found >= matches && matches > 0) break; - - if ((distance = re_matchp(regex, &lines[index][offset], &len)) == -1) { - break; - } - - if (distance > 0) { - expand_string(&buf, &capacity, &size, &lines[index][offset], distance); - } - - expand_string(&buf, &capacity, &size, sub, sub_len); - offset += len + distance; - matches_found++; - } - - left = strlen(lines[index] + offset); - expand_string(&buf, &capacity, &size, &lines[index][offset], left + 1); - - free(lines[index]); - lines[index] = buf; - return matches_found; -} - -static void prompt(void) { - char buf[INPUT_LEN]; - char* index; - char cmd; - bool whitespace, linenumbers; - struct LineAddress address; - - printf(": "); - fflush(stdout); - - if (ed_getline(buf, INPUT_LEN) == EOF) { putchar('\n'); return; } - if (buf[0] == '\0') { putchar('\n'); return; } - - index = &buf[0]; - whitespace = skip_whitespace(&index); - - if (!read_address(&index, whitespace, &address)) return; - - cmd = *(index++); - - if (cmd == ',') { - struct LineAddress address2; - - if (address.type != INDEX) { - error_s("comma range addressing requires two index addresses\n"); - free_address(address); - return; - } - - whitespace = skip_whitespace(&index); - - if (!read_address(&index, whitespace, &address2)) { - free_address(address); - return; - } - - if (address2.type != INDEX) { - error_s("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) { - error_s("range addressing must be in ascending order\n"); - free_address(address); - return; - } - - linenumbers = false; - -test: - switch (cmd) { - case '\0': - case '\n': - if (address.empty) { - if (line_current == line_count) { - error_s("line number %ld does not exist\n", line_current + 1); - break; - } else if (line_current + 1 == line_count) { - error_s("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) { - error_s("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 'n': - linenumbers = true; - __attribute__((fallthrough)); - case 'p': - if (address.empty && address.data.index.i >= (long int) line_count) { - error_s("line number %ld does not exist\n", address.data.index.i + 1); - break; - } - if (address.type == INDEX) { - if (linenumbers) printf("%ld\t", address.data.index.i + 1); - printf("%s", lines[address.data.index.i]); - } else if (address.type == RANGE) { - long int i; - for (i = address.data.range.a; i <= address.data.range.b; i++) { - if (linenumbers) printf("%ld\t", i + 1); - printf("%s", lines[i]); - } - } else if (address.type == SET) { - unsigned long i; - for (i = 0; i < address.data.set.s; i++) { - if (linenumbers) printf("%ld\t", address.data.set.b[i] +1); - printf("%s", lines[address.data.set.b[i]]); - } - } - break; - case 'q': - if (!check_if_sure("Quit for sure? ")) break; - __attribute__((fallthrough)); - case 'Q': - free_address(address); - free_data(true); - exit(EXIT_SUCCESS); - break; - case 'g': - skip_whitespace(&index); - free_address(address); - if (*(index++) != '/') { - error_s("unexpected character at start of regex\n"); - break; - } - if (!parse_regex(&index, &address, ALL)) { return; } - skip_whitespace(&index); - if (*index == '\n' || *index == '\0') { - cmd = 'p'; - } else { - cmd = *(index++); - } - goto test; - break; - case 's': { - char* replace = index; - long int matches, sub_len, matches_found; - unsigned long i; - - skip_whitespace(&index); - if (*(index++) != '/') { - error_s("unexpected character at start of regex\n"); - break; - } - if (!parse_regex_lines(&index, &address)) { return; } - while(*index != '\0' && *index != '/') index++; - if (*index != '/') { - error_s("/ missing after %c\n", *index); - break; - } - if (address.data.set.s < 1) { - error_s("no matches found\n"); - break; - } - *(index++) = '\0'; - if (*index == '\0' || *index == '\n') { - matches = 1; - } else if (*index == 'g') { - matches = -1; - } else { - char* end; - matches = strtol(index, &end, 10); - if (end == index) { - error_s("invalid number: %s\n", index); - break; - } - if (matches < 1) { - error_s("matches cannot be less than 1\n"); - break; - } - } - sub_len = strlen(replace); - matches_found = 0; - - for (i = 0; i < address.data.set.s; i++) { - matches_found += substute_string(address.data.set.b[i], matches, last_regex, replace, sub_len); - } - output("replaced %ld matches over %ld lines\n", matches_found, address.data.set.s); - pending_writes = true; - break; - } - case 'w': { - bool quit = false; - if (*index == 'q') { - index++; - quit = true; - } - skip_whitespace(&index); - write_file(index, &address, "w"); - if (quit) { - free_address(address); - free_data(true); - exit(EXIT_SUCCESS); - } - break; - } - case 'r': { - skip_whitespace(&index); - read_file(index); - break; - } - case 'e': - if (!check_if_sure("Load new file for sure? ")) break; - __attribute__((fallthrough)); - case 'E': { - char* filename; - FILE* file; - - skip_whitespace(&index); - - filename = index; - if(!get_file_name(&filename)) break; - - file = get_file_s(filename, "r"); - if (file == NULL) break; - - load_file(file); - break; - } - case 'W': - skip_whitespace(&index); - write_file(index, &address, "a"); - break; - case '=': - printf("%ld\n", line_current + 1); - break; - default: - error_s("unimplemented command\n"); - break; - } - - free_address(address); - -} - -static void prompt_loop(void) { - while (true) { - prompt(); - } -} - -static void help(void) { - printf("Usage: ed [FILE]\n\n"); - printf("Edit a given [FILE] or create a new text file\n\n"); - printf("\t(.,.)\tnewline\t\tgo to address line and print\n"); - printf("\t(.)\ta\t\tappend new data after given line\n"); - printf("\t(.,.)\tc\t\treplace given lines with new data\n"); - printf("\t(.,.)\td\t\tdelete given lines\n"); - printf("\t\te file\t\tdelete current buffer and edit file\n"); - printf("\t\tE file\t\tdelete current buffer and edit file unconditionally\n"); - printf("\t\tg/re/command\tgrep all lines with regex and run command on matches\n"); - printf("\t(.,.)\tn\t\tprint given lines along with their line numbers\n"); - printf("\t(.,.)\tp\t\tprint given lines\n"); - printf("\t\tq\t\tquit file\n"); - printf("\t\tQ\t\tquit file unconditionally\n"); - printf("\t($)\tr file\t\tread file and append to end of buffer\n"); - printf("\t(.,.)\ts/re/replace/\treplace the first match on each matching line\n"); - printf("\t(.,.)\ts/re/replace/g\treplace all matches on each matching line\n"); - printf("\t(.,.)\ts/re/replace/n\treplace n matches on each matching line\n"); - printf("\t(.,.)\tw file\t\twrite contents of lines to file\n"); - printf("\t(.,.)\twq file\t\twrite contents of lines to file then quit\n"); - printf("\t(.,.)\tW file\t\tappend contents of line to file\n"); - printf("\t\t=\t\tprint current line number\n"); -} - -COMMAND(ed) { - - parse_help(argc, argv, help); - - if (argc < 1) { - load_empty(); - prompt_loop(); - } else { - FILE* file = get_file(argv[0], "r"); - load_file(file); - get_file_name(&argv[0]); - prompt_loop(); - } - return EXIT_SUCCESS; -} diff --git a/src/commands/grep.c b/src/commands/grep.c deleted file mode 100644 index 4062734..0000000 --- a/src/commands/grep.c +++ /dev/null @@ -1,265 +0,0 @@ -#include "../command.h" -#include <stdio.h> - -static struct { - bool filename_prefix; - bool never_file_prefix; - bool line_number; - bool only_matching_names; - bool only_non_matching_names; - bool only_line_count; - bool only_matching_part; - bool quiet; - bool inverse; - bool ignore_case; - bool is_regex; -} flags; - -static int short_arg(char c, char* next) { - UNUSED(next); - switch (c) { - case 'H': - flags.filename_prefix = true; - break; - case 'h': - flags.never_file_prefix = true; - break; - case 'n': - flags.line_number = true; - break; - case 'l': - flags.only_matching_names = true; - break; - case 'L': - flags.only_non_matching_names = true; - break; - case 'c': - flags.only_line_count = true; - break; - case 'o': - flags.only_matching_part = true; - break; - case 'q': - flags.quiet = true; - break; - case 'v': - flags.inverse = true; - break; - case 'i': - flags.ignore_case = true; - break; - case 'F': - flags.is_regex = false; - break; - case 'E': - flags.is_regex = true; - break; - default: - return ARG_INVALID; - } - return ARG_UNUSED; -} - -static void help(void) { - printf("Usage: grep [-HhlLoqviFE] [-m N] PATTERN [FILE]...\n"); - printf("Search for PATTERN in FILEs (or stdin)\n"); - printf("\t-H\tAdd 'filename:' prefix\n"); - printf("\t-h\tDo not add 'filename:' prefix\n"); - printf("\t-n\tAdd 'line_no:' prefix\n"); - printf("\t-l\tShow only names of files that match\n"); - printf("\t-L\tShow only names of files that don't match\n"); - printf("\t-c\tShow only count of matching lines\n"); - printf("\t-o\tShow only the matching part of line\n"); - printf("\t-q\tQuiet. Return 0 if PATTERN is found, 1 otherwise\n"); - printf("\t-v\tSelect non-matching lines\n"); - printf("\t-i\tIgnore case\n"); - printf("\t-F\tPATTERN is a literal (not regexp)\n"); - printf("\t-E\tPATTERN is an extended regexp\n"); -} - -static bool match_regex(char** string, re_t pattern) { - int len; - int index; - if ((index = re_matchp(pattern, *string, &len)) < 0) return false; - if (flags.only_matching_part) { - (*string) += index; - (*string)[len] = '\0'; - } - return true; -} - -static bool match_literal(char** string, char* pattern) { - char* match = *string; - size_t match_len = strlen(match); - size_t pattern_len = strlen(pattern); - size_t i; - - if (match_len < pattern_len) return false; - - for (i = 0; i < match_len - pattern_len + 1; i++) { - if ( - (!flags.ignore_case && strncmp(match + i, pattern, pattern_len) == 0) || - (flags.ignore_case && strncasecmp(match + i, pattern, pattern_len) == 0) - ) { - if (flags.only_matching_part) { - *string = (*string) + i; - (*string)[pattern_len] = '\0'; - } - return true; - } - } - - return false; -} - -static bool match(char** string, void* pattern) { - bool result; - if (flags.is_regex) { - result = match_regex(string, (re_t) pattern); - } else { - result = match_literal(string, (char*) pattern); - } - return (flags.inverse ? !result : result); -} - -static bool match_any(char* path, void* pattern) { - FILE* file; - char* buf = NULL; - size_t offset; - bool matched = false; - int read; - - file = get_file_s(path, "r"); - if (file == NULL) return false; - - while ((read = getline(&buf, &offset, file)) > 0) { - char* save = buf; - if (buf[read-1] == '\n') buf[read-1] = '\0'; - if (match(&save, pattern)) { - matched = true; - break; - } - } - - if (buf != NULL) free(buf); - - return matched; -} - -static bool match_file(char* path, void* pattern, bool many) { - FILE* file; - char* buf = NULL; - size_t offset; - int num_matched = 0; - int line_num = 0; - int read; - - file = get_file_s(path, "r"); - if (file == NULL) return false; - - while((read = getline(&buf, &offset, file)) > 0) { - char* matched = buf; - - if (buf[read-1] == '\n') buf[read-1] = '\0'; - line_num++; - - if (!match(&matched, pattern)) { - continue; - } - - num_matched++; - - if (flags.only_line_count || flags.quiet) continue; - - if ((many || flags.filename_prefix) && !flags.never_file_prefix) { - print_file_path(path); - putchar(':'); - } - - if (flags.line_number) { - printf("%d:", line_num); - } - - if (flags.only_matching_part) { - printf("%s\n", matched); - } else { - printf("%s\n", buf); - } - } - - if (!flags.quiet && flags.only_line_count) { - if ((many || flags.filename_prefix) && !flags.never_file_prefix) { - print_file_path(path); - putchar(':'); - } - printf("%d\n", num_matched); - } - - if (buf != NULL) free(buf); - - return num_matched != 0; -} - -static void* compile(char* pattern) { - if (flags.is_regex) { - return re_compile(pattern); - } else { - return pattern; - } -} - -static bool run_match(char* path, void* pattern, bool many) { - bool result; - if (flags.only_matching_names || flags.only_non_matching_names) { - result = match_any(path, pattern); - if (flags.only_non_matching_names) result = !result; - if (result && !flags.quiet) { - print_file_path(path); - putchar('\n'); - } - return result; - } else { - return match_file(path, pattern, many); - } -} - -COMMAND(grep) { - - int start, i; - char* pattern; - bool many, ok; - void* compiled; - - flags.only_matching_part = false; - flags.only_non_matching_names = false; - flags.only_matching_names = false; - flags.only_line_count = false; - flags.quiet = false; - flags.is_regex = true; - flags.line_number = false; - flags.never_file_prefix = false; - flags.filename_prefix = false; - flags.inverse = false; - - start = parse_args(argc, argv, help, short_arg, NULL); - - if (argc - start < 1) global_help(help); - - pattern = argv[start++]; - - many = argc - start > 0; - ok = false; - - compiled = compile(pattern); - if (run_match("-", compiled, many)) ok = true; - - for (i = start; i < argc; i++) { - if (run_match(argv[i], compiled, many)) ok = true; - } - - if (flags.quiet) { - return ok ? EXIT_SUCCESS : EXIT_FAILURE; - } else { - return EXIT_SUCCESS; - } -} diff --git a/src/commands/groups.c b/src/commands/groups.c deleted file mode 100644 index bd2e5f9..0000000 --- a/src/commands/groups.c +++ /dev/null @@ -1,42 +0,0 @@ -#include "../command.h" - -#include <grp.h> -#include <pwd.h> - -COMMAND_EMPTY(groups) { - - uid_t uid; - int ngroups, i; - gid_t* groups; - struct passwd* pw; - - uid = getuid(); - - pw = getpwuid(uid); - if(pw == NULL){ - error("failed to fetch groups: %s", strerror(errno)); - } - - ngroups = 0; - getgrouplist(pw->pw_name, pw->pw_gid, NULL, &ngroups); - - groups = malloc(sizeof(gid_t) * ngroups); - getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups); - - for (i = 0; i < ngroups; i++){ - struct group* gr = getgrgid(groups[i]); - - if(gr == NULL) { - free(groups); - error("failed to fetch groups: %s", strerror(errno)); - } - - printf("%s ",gr->gr_name); - } - - printf("\n"); - - free(groups); - - return EXIT_SUCCESS; -} diff --git a/src/commands/head.c b/src/commands/head.c deleted file mode 100644 index da8b9b3..0000000 --- a/src/commands/head.c +++ /dev/null @@ -1,138 +0,0 @@ -#include "../command.h" - -static struct { - int count; - bool lines; - bool print_headers; - bool dont_print_headers; -} flags; - -static void head_file_lines(FILE* file) { - size_t len = 0; - char* line = NULL; - - int count = flags.count; - while(count > 0 && getline(&line, &len, file) != -1) { - printf("%s", line); - count--; - } - - free(line); - fclose(file); -} - -static void head_file_chars(FILE* file) { - char c; - int count = flags.count; - while(count > 0 && (c = getc(file)) != EOF) { - putchar(c); - count--; - } - - fclose(file); -} - -static void help(void) { - printf("Usage: head [OPTIONS] [FILE]...\n\n"); - printf("Print first 10 lines of FILEs (or stdin)\n"); - printf("With more than one FILE, precede each with a filename header.\n\n"); - printf("\t-c [+]N[bkm]\tPrint first N bytes\n"); - printf("\t-n N[bkm]\tPrint first N lines\n"); - printf("\t\t\t(b:*512 k:*1024 m:*1024^2)\n"); - printf("\t-q\t\tNever print headers\n"); - printf("\t-v\t\tAlways print headers\n"); -} - -static void print_header(char* path, bool many) { - if (flags.dont_print_headers) return; - if (!many && !flags.print_headers) return; - if (streql("-", path)) { - printf("\n==> standard input <==\n"); - } else { - printf("\n=>> %s <==\n", path); - } -} - -static void head_file(char* path, bool many) { - FILE* file = get_file(path, "r"); - print_header(path, many); - if (flags.lines) { - head_file_lines(file); - } else { - head_file_chars(file); - } -} - -static int short_arg(char c, char* next) { - switch(c) { - case 'c': { - long int bkm; - - flags.lines = false; - - check_arg(next); - bkm = get_blkm(next); - - if (bkm < 1) { - error("bkm cannot be less than 1"); - } - - flags.count = bkm; - return ARG_USED; - } - case 'n': { - long int bkm; - - flags.lines = true; - - check_arg(next); - bkm = get_blkm(next); - - if (bkm < 1) { - error("bkm cannot be less than 1"); - } - - flags.count = bkm; - return ARG_USED; - } - case 'q': - flags.dont_print_headers = true; - break; - case 'v': - flags.print_headers = true; - break; - default: - return ARG_INVALID; - } - return ARG_UNUSED; -} - -COMMAND(head) { - - int start, count, i; - - flags.count = 10; - flags.lines = true; - flags.print_headers = false; - flags.dont_print_headers = false; - - start = parse_args(argc, argv, help, short_arg, NULL); - - count = argc - start; - - if (count < 1) { - head_file_lines(stdin); - return EXIT_SUCCESS; - } - - if (count == 1) { - head_file(argv[start], false); - return EXIT_SUCCESS; - } - - for (i = 0; i < count; i++) { - head_file(argv[start + i], true); - } - - return EXIT_SUCCESS; -} diff --git a/src/commands/id.c b/src/commands/id.c deleted file mode 100644 index 3bef4f6..0000000 --- a/src/commands/id.c +++ /dev/null @@ -1,53 +0,0 @@ -#include "../command.h" - -#include <grp.h> -#include <pwd.h> - -COMMAND_EMPTY(user_id) { - - uid_t uid; - gid_t gid, *groups; - int ngroups, i; - struct passwd* pw; - struct group* ugr; - - uid = getuid(); - gid = getgid(); - - pw = getpwuid(uid); - if(pw == NULL){ - error("failed to fetch groups: %s", strerror(errno)); - } - - ngroups = 0; - getgrouplist(pw->pw_name, pw->pw_gid, NULL, &ngroups); - - groups = malloc(sizeof(gid_t) * ngroups); - getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups); - - ugr = getgrgid(gid); - printf("uid=%d(%s) gid=%d(%s) ", - uid, ugr->gr_name, gid, ugr->gr_name); - - if (ngroups > 0) { - printf("groups="); - } - - for (i = 0; i < ngroups; i++){ - struct group* gr = getgrgid(groups[i]); - if(gr == NULL) { - free(groups); - error("failed to fetch groups: %s", strerror(errno)); - } - - printf("%d(%s)", gr->gr_gid, gr->gr_name); - - if (i + 1 < ngroups) putchar(','); - } - - printf("\b\n"); - - free(groups); - - return EXIT_SUCCESS; -} diff --git a/src/commands/ls.c b/src/commands/ls.c deleted file mode 100644 index e8d58d0..0000000 --- a/src/commands/ls.c +++ /dev/null @@ -1,552 +0,0 @@ -#include "../command.h" - -#include <grp.h> -#include <pwd.h> -#include <dirent.h> -#include <ftw.h> -#include <limits.h> -#include <string.h> - -#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 NORMAL 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 -#define SOCK_COLOR ANSCII BOLD NEXT NORMAL MAGENTA COLOR - -static struct { - bool hidden; - bool hide_dot; - bool more_info; - bool one_column; - bool recurse; - enum When colored; -} flags; - -struct FileInfo { - struct passwd* usr; - struct group* grp; - char* name; - char date[13]; - char mode[11]; - char size[5]; - int links; - int bytes; - bool set_uid; - bool set_gid; - bool exec; - unsigned char type; -}; - -struct FileListInfo { - int max_link; - int max_usr; - int max_grp; - int max_size; - int max_name; - int total_len; - int total_size; -}; - -static DIR* get_directory(char* path) { - DIR* d = opendir(path); - if (d == NULL) { - if (errno == ENOTDIR) { - error_s("`%s` is a a file\n", path); - } else { - error_s("failed to open directory '%s': %s\n", path, strerror(errno)); - } - } - return d; -} - -static bool get_file_info(const char* file_name, struct FileInfo* info) { - - uid_t uid; - gid_t gid; - int save, ty; - struct stat s; - size_t file_len; - - uid = getuid(); - gid = getgid(); - - memset(&s, 0, sizeof(struct stat)); - - save = push_path_buffer(file_name); - - if (lstat(get_path_buffer(), &s) < 0) { - error_s("failed to read file '%s': %s\n", get_path_buffer(), strerror(errno)); - pop_path_buffer(save); - return false; - } - - ty = (s.st_mode & S_IFMT) >> 12; - - info->set_uid = false; - info->set_gid = false; - info->exec = false; - - 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) { - if (s.st_mode & S_ISUID) { - info->mode[3] = 's'; - info->set_uid = true; - } else { - info->mode[3] = 'x'; - } - if (!info->exec) info->exec = s.st_uid == uid; - } else { - info->mode[3] = '-'; - } - - info->mode[4] = (s.st_mode & S_IRGRP) ? 'r' : '-'; - info->mode[5] = (s.st_mode & S_IWGRP) ? 'w' : '-'; - if (s.st_mode & S_IXGRP) { - if (s.st_mode & S_ISGID) { - info->mode[6] = 's'; - info->set_gid = true; - } else { - info->mode[6] = 'x'; - } - if (!info->exec) info->exec = s.st_gid == gid; - } else { - info->mode[6] = '-'; - } - - info->mode[7] = (s.st_mode & S_IROTH) ? 'r' : '-'; - info->mode[8] = (s.st_mode & S_IWOTH) ? 'w' : '-'; - if (s.st_mode & S_IXOTH) { - info->mode[9] = 'x'; - info->exec = true; - } else { - info->mode[9] = '-'; - } - - info->mode[10] = '\0'; - - info->usr = getpwuid(s.st_uid); - if (info->usr == NULL) { - error_s("failed to get user from `%s`\n", get_path_buffer()); - pop_path_buffer(save); - return false; - } - - info->grp = getgrgid(s.st_gid); - if (info->grp == NULL) { - error_s("failed to get user from `%s`\n", get_path_buffer()); - pop_path_buffer(save); - return false; - } - - info->links = s.st_nlink; - info->type = ty; - - file_len = strlen(file_name) + 1; - info->name = malloc(file_len); - memcpy(info->name, file_name, file_len); - - print_file_size(s.st_size, info->size); - print_date_time(s.st_mtim.tv_sec + s.st_mtim.tv_nsec / 1000000000, info->date); - - info->bytes = (s.st_size + s.st_blksize - 1) / s.st_blksize; - - pop_path_buffer(save); - return true; -} - -static char* get_file_color(struct FileInfo* info) { - char* color; - if (info->type == DT_DIR) { - 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_SOCK) { - color = SOCK_COLOR; - } else if ( - info->type == DT_CHR || - info->type == DT_BLK - ) { - color = BLK_COLOR; - } else { - if (info->set_uid) { - color = SET_UID_COLOR; - } else if (info->set_gid) { - color = SET_GID_COLOR; - } else if (info->exec) { - color = EXEC_COLOR; - } else { - color = FILE_COLOR; - } - } - return color; -} - -static void list_files(struct FileInfo* files, int file_len, struct FileListInfo info) { - - struct winsize w; - char* color; - int column_width, row_count, i; - - if (flags.more_info) { - char total[13]; - print_file_size(info.total_size, total); - printf("total %s\n", total); - } - - ioctl(STDOUT_FILENO, TIOCGWINSZ, &w); - - if (!isatty(1)) { - flags.one_column = true; - if (flags.colored == AUTO) - flags.colored = NO; - } - - column_width = info.max_name + 1; - row_count = w.ws_col / column_width; - - for (i = 0; i < file_len; i++) { - struct FileInfo finfo = files[i]; - color = get_file_color(&finfo); - if (flags.more_info) { - printf("%s %*d %*s %*s %*s %s %s%s%s", - finfo.mode, - info.max_link, - finfo.links, - info.max_usr, - finfo.usr->pw_name, - info.max_grp, - finfo.grp->gr_name, - info.max_size, - finfo.size, - finfo.date, - flags.colored != NO ? color : "", - finfo.name, - flags.colored != NO ? "\x1b[0m" : "" - ); - if (finfo.type == DT_LNK) { - int save = push_path_buffer(finfo.name); - - char lnk[PATH_MAX]; - ssize_t n; - if ((n = readlink(get_path_buffer(), lnk, PATH_MAX)) != -1) { - printf(" -> %.*s\n", (int)n, lnk); - } else { - putchar('\n'); - } - - pop_path_buffer(save); - } else { - putchar('\n'); - } - } else if (flags.one_column) { - printf("%s%s%s\n", flags.colored != NO ? 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%s", flags.colored != NO ? color : "", -column_width, - finfo.name, flags.colored != NO ? "\x1b[0m" : ""); - } else { - printf("%s%s%s ", flags.colored != NO ? color : "", finfo.name, - flags.colored != NO ? "\x1b[0m" : ""); - } - } - free(finfo.name); - } - - if (!flags.more_info) printf("\n"); -} - -static int num_places (int n) { - int r = 1; - if (n < 0) n = (n == INT_MIN) ? INT_MAX: -n; - while (n > 9) { - n /= 10; - r++; - } - return r; -} - -static void push_file( - struct FileInfo** files, - struct FileListInfo* info, - int* size, int* capacity, - const char* file_path -) { - struct FileInfo finfo; - int user_len, group_len, name_len, size_len, link_len; - - if (!get_file_info(file_path, &finfo)) return; - - if (*size == *capacity) { - *capacity *= 2; - *files = realloc(*files, sizeof(struct FileInfo) * *capacity); - } - - user_len = strlen(finfo.usr->pw_name); - if (user_len > info->max_usr) info->max_usr = user_len; - - group_len = strlen(finfo.grp->gr_name); - if (group_len > info->max_grp) info->max_grp = group_len; - - name_len = strlen(file_path); - if (name_len > info->max_name) info->max_name = name_len; - - size_len = strlen(finfo.size); - if (size_len > info->max_size) info->max_size = size_len; - - link_len = num_places(finfo.links); - if (link_len > info->max_link) info->max_link = link_len; - - info->total_len += name_len + 2; - info->total_size += finfo.bytes; - - (*files)[*size] = finfo; - (*size)++; -} - -static void recurse_directory(char* dir_name) { - DIR* d; - int capacity, size, save; - struct dirent* file; - struct FileInfo* files; - struct FileListInfo info; - - save = push_path_buffer(dir_name); - - d = get_directory(get_path_buffer()); - if (d == NULL) { - return; - } - - capacity = 8; - size = 0; - - files = malloc(sizeof(struct FileInfo) * capacity); - memset(&info, 0, sizeof(struct FileListInfo)); - - while((file = readdir(d)) != NULL) { - if (!flags.hidden && prefix(".", file->d_name)) continue; - if (flags.hide_dot && is_dot_dir(file->d_name)) continue; - if (file->d_type == DT_DIR && !is_dot_dir(file->d_name)) { - recurse_directory(file->d_name); - } else { - push_file(&files, &info, &size, &capacity, file->d_name); - } - } - - - if (flags.colored == NO) { - printf("\n%s:\n", get_path_buffer()); - } else { - printf("\n%s%s:%s\n", DIR_COLOR, get_path_buffer(), FILE_COLOR); - } - - list_files(files, size, info); - - free(files); - - if (!flags.more_info) printf("\n"); - - closedir(d); - - pop_path_buffer(save); -} - -static void list_directory(char* path) { - - DIR* d; - int capacity, size, save; - struct FileInfo* files; - struct FileListInfo info; - struct dirent* file; - - if (flags.recurse) { - recurse_directory(path); - return; - } - - d = get_directory(path); - if (d == NULL) return; - - save = push_path_buffer(path); - - capacity = 8; - size = 0; - - files = malloc(sizeof(struct FileInfo) * capacity); - memset(&info, 0, sizeof(struct FileListInfo)); - - 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->d_name); - } - - if (size > 0) list_files(files, size, info); - free(files); - - pop_path_buffer(save); - - closedir(d); -} - -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) { - - int capacity, size, i; - struct FileInfo* files; - struct FileListInfo info; - - capacity = 8; - size = 0; - - files = malloc(sizeof(struct FileInfo) * capacity); - memset(&info, 0, sizeof(struct FileListInfo)); - - for (i = start; i < argc; i++) { - if (is_dir(argv[i])) continue; - push_file(&files, &info, &size, &capacity, argv[i]); - } - - if (size > 0) list_files(files, size, info); - - free(files); -} - -static void help(void) { - printf("Usage: ls [FILE]...\n\n"); - printf("List directory contents\n\n"); - printf("\t-1\tOne column output\n"); - printf("\t-l\tLong format\n"); - printf("\t-a\tInclude names starting with .\n"); - printf("\t-A\tLike -a but without . and ..\n"); - printf("\t-R\tRecurse\n"); -} - -static int short_arg(char c, char* next) { - UNUSED(next); - switch (c) { - case 'R': - flags.recurse = true; - break; - case '1': - flags.one_column = true; - break; - case 'A': - flags.hide_dot = true; - flags.hidden = true; - break; - case 'a': - flags.hidden = true; - break; - case 'l': - flags.more_info = true; - break; - default: - return ARG_INVALID; - } - return ARG_UNUSED; -} - -static int long_arg(char* cur, char* next) { - UNUSED(next); - if (prefix("--color=", cur)) { - char* arg = cur + 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("invalid color options: %s", arg); - } - } else { - return ARG_IGNORE; - } - return ARG_UNUSED; -} - -COMMAND(ls) { - - int start, i; - bool titled; - - flags.hidden = false; - flags.more_info = false; - flags.hide_dot = false; - flags.one_column = false; - flags.recurse = false; - flags.colored = NO; - - start = parse_args(argc, argv, help, short_arg, long_arg); - - if (argc - start == 0) { - list_directory("."); - return EXIT_SUCCESS; - } - - list_file_args(start, argc, argv); - - titled = argc - start > 1; - for (i = start; i < argc; i++) { - - if (!is_dir(argv[i])) continue; - - if (titled && !flags.recurse) { - if (flags.colored != NO) { - printf("\n%s%s:%s\n", DIR_COLOR, argv[i], FILE_COLOR); - } else { - printf("\n%s:\n", argv[i]); - } - } - - list_directory(argv[i]); - } - - return EXIT_SUCCESS; -} diff --git a/src/commands/mkdir.c b/src/commands/mkdir.c deleted file mode 100644 index 02fccca..0000000 --- a/src/commands/mkdir.c +++ /dev/null @@ -1,65 +0,0 @@ -#include "../command.h" - -static struct { - bool make_parent; - mode_t mode; -} flags; - -static int short_arg(char c, char* next) { - switch (c) { - case 'p': - flags.make_parent = true; - break; - case 'm': - check_arg(next); - flags.mode = get_mode(next); - return ARG_USED; - default: - return ARG_INVALID; - } - return ARG_UNUSED; -} - -static void help(void) { - printf("Usage: mkdir [-m MODE] [-p] DIRECTORY...\n\n"); - printf("Create DIRECTORY\n\n"); - printf("\t-m\tMODE\n"); - printf("\t-p\tNo error if exists; make parent directories as needed\n"); -} - -static bool mkdir_parents(char* path) { - size_t i; - for (i = 1; i < strlen(path); i++) { - if (path[i] != '/') continue; - path[i] = '\0'; - if (mkdir(path, flags.mode) < 0 && errno != EEXIST) { - error_s("failed to create directory '%s': %s", path, strerror(errno)); - return false; - }; - path[i] = '/'; - } - return true; -} - -COMMAND(makedir) { - - int start, i; - - if (argc < 1) global_help(help); - - flags.make_parent = false; - flags.mode = 0755; - - start = parse_args(argc, argv, help, short_arg, NULL); - - for (i = start; i < argc; i++) { - if (flags.make_parent && !mkdir_parents(argv[i])) { - continue; - } - if (mkdir(argv[i], flags.mode) < 0) { - error_s("failed to create directory '%s': %s", argv[i], strerror(errno)); - } - } - - return EXIT_SUCCESS; -} diff --git a/src/commands/mv.c b/src/commands/mv.c deleted file mode 100644 index d203607..0000000 --- a/src/commands/mv.c +++ /dev/null @@ -1,116 +0,0 @@ -#include "../command.h" - -static struct { - bool prompt; - bool dont_overwrite; - bool refuse_if_dir; - bool verbose; -} flags; - -static void help(void) { - printf("Usage: mv [-inT] SOURCE... DIRECTORY\n\n"); - printf("Rename SOURCE to DEST, or move SOURCEs to DIRECTORY\n"); - printf("\t-i\tInteractive, prompt before overwriting\n"); - printf("\t-n\tDon't overwrite an existing file\n"); - printf("\t-T\tRefuse to move if DEST is a directory\n"); - printf("\t-v\tVerbose\n"); -} - -static int short_arg(char c, char* next) { - UNUSED(next); - switch (c) { - case 't': - flags.prompt = true; - break; - case 'n': - flags.dont_overwrite = true; - break; - case 'T': - flags.refuse_if_dir = true; - break; - case 'v': - flags.verbose = true; - break; - default: - return ARG_UNUSED; - } - return ARG_USED; -} - -static void mv_dir(bool exists) { - - char c; - - if (exists && flags.dont_overwrite) { - if (flags.verbose) output("skipping '%s'; overwrise is false", get_path_buffer_2()); - return; - } - - if (exists && flags.prompt) { - fprintf(stderr, "overwrite '%s'? ", get_path_buffer_2()); - fflush(stderr); - - c = getchar(); - if (c != 'y' && c != 'Y') { - if (flags.verbose) output("skipping..."); - return; - } - - } - - if (rename(get_path_buffer(), get_path_buffer_2()) < 0) { - error_s("cannot move '%s': %s", get_path_buffer(), strerror(errno)); - } else if (flags.verbose) { - output("moved '%s'", get_path_buffer()); - } -} - -COMMAND(mv) { - - int start, dest, i; - struct stat s; - - flags.refuse_if_dir = false; - flags.dont_overwrite = false; - flags.prompt = false; - flags.verbose = false; - - start = parse_args(argc, argv, help, short_arg, NULL); - - if (argc - start < 2) { - global_help(help); - } - - push_path_buffer_2(argv[argc-1]); - - dest = true; - if (lstat(get_path_buffer_2(), &s) < 0 && argc - start > 2) { - dest = false; - error("cannot stat '%s': %s", get_path_buffer_2(), strerror(errno)); - } - - if (dest && flags.refuse_if_dir) { - if (S_ISDIR(s.st_mode)) { - error("target '%s': Is A Directory", get_path_buffer_2()); - } - } - - if (argc - start == 2) { - push_path_buffer(argv[argc-2]); - mv_dir(dest); - return EXIT_SUCCESS; - } - - if (dest && !S_ISDIR(s.st_mode)) { - error("target '%s': Is Not A Directory", get_path_buffer_2()); - } - - for (i = start; i < argc - 1; i++) { - int save = push_path_buffer(argv[i]); - bool exists = lstat(get_path_buffer(), &s) >= 0; - mv_dir(exists); - pop_path_buffer(save); - } - - return EXIT_SUCCESS; -} diff --git a/src/commands/printf.c b/src/commands/printf.c deleted file mode 100644 index 519b8a2..0000000 --- a/src/commands/printf.c +++ /dev/null @@ -1,141 +0,0 @@ -#include "../command.h" - -static long cast_long(const char* arg) { - char* end; - long l = strtol(arg, &end, 10); - if (end == arg) { - return 0; - } else { - return l; - } -} - -static double cast_double(const char* arg) { - char* end; - double d = strtod(arg, &end); - if (end == arg) { - return 0.0; - } else { - return d; - } -} - -#define NUMBER(name, type, arg) \ - long l = cast_long(arg); \ - type* t = (type*) &l; \ - type name = *t; - -static void handle_percent(char n, const char* arg) { - switch (n) { - case 'd': - case 'z': { - NUMBER(i, int, arg) - printf("%d", i); - break; - } - case 'u': { - NUMBER(u, unsigned int, arg); - printf("%u", u); - break; - } - case 'f': { - double d = cast_double(arg); - printf("%f", d); - break; - } - case 'c': { - putchar(arg[0]); - break; - } - case 's': { - printf("%s", arg); - break; - } - default: { - putchar('%'); - putchar(n); - } - } -} - -static void handle_slash(char n) { - switch (n) { - case 'n': - putchar('\n'); - break; - case 't': - putchar('\t'); - break; - case 'v': - putchar('\v'); - break; - case 'b': - putchar('\b'); - break; - case 'f': - putchar('\f'); - break; - case 'a': - putchar('\a'); - break; - case '"': - putchar('"'); - break; - case 'c': - exit(EXIT_SUCCESS); - default: - putchar('\\'); - putchar(n); - } -} - -static void help(void) { - printf("Usage printf FORMAT [ARG]...\n\n"); - printf("Format and print ARG(s) according to FORMAT (a-la C prinf)\n"); -} - -COMMAND(print) { - - size_t index; - int arg_index; - char n, *arg; - - if (argc < 1) { - global_help(help); - return EXIT_SUCCESS; - } - - parse_help(argc, argv, help); - - index = 0; - arg_index = 0; - - while (true) { - char c = argv[0][index]; - index++; - - if (c == '\0') break; - if (c != '%' && c != '\\') { - putchar(c); - continue; - } - - n = argv[0][index]; - index++; - - arg = NULL; - if (arg_index < argc) { - arg = argv[arg_index + 1]; - } - - if (c == '%') { - handle_percent(n, arg); - } else { - handle_slash(n); - } - - arg_index++; - } - - return EXIT_SUCCESS; -} diff --git a/src/commands/rm.c b/src/commands/rm.c deleted file mode 100644 index 8ce3e1c..0000000 --- a/src/commands/rm.c +++ /dev/null @@ -1,136 +0,0 @@ -#include "../command.h" -#include <dirent.h> -#include <string.h> - -static struct { - bool force; - bool prompt; - bool verbose; - bool recurse; -} flags; - -static void help(void) { - printf("Usage: rm [-irfv] FILE...\n\n"); - printf("Remove (unlink) FILESs\n\n"); - printf("\t-i\tAlways prompt before removing\n"); - printf("\t-f\tForce, never prompt\n"); - printf("\t-v\tVerbose\n"); - printf("\t-R,-r\tRecurse\n"); -} - -static int short_arg(char c, char* next) { - UNUSED(next); - switch (c) { - case 'i': - flags.prompt = true; - break; - case 'f': - flags.force = true; - break; - case 'v': - flags.verbose = true; - break; - case 'R': - case 'r': - flags.recurse = true; - break; - default: - return ARG_INVALID; - } - return ARG_UNUSED; -} - -static void rm_file (char* path); - -static bool rm_dir (void) { - DIR* d; - struct dirent* file; - - d = opendir(get_path_buffer()); - if (d == NULL) { - error_s("failed to stat '%s': %s\n", get_path_buffer(), strerror(errno)); - return false; - } - - while ((file = readdir(d)) != NULL) { - if (is_dot_dir(file->d_name)) continue; - rm_file(file->d_name); - } - - closedir(d); - return true; -} - -static void rm_file(char* path) { - int save = push_path_buffer(path); - - struct stat s; - if (lstat(get_path_buffer(), &s) < 0) { - pop_path_buffer(save); - error_s("failed to stat '%s': %s\n", get_path_buffer(), strerror(errno)); - return; - } - - if (S_ISDIR(s.st_mode)) { - if (!flags.force) { - error_s("cannot delete '%s': Is a directory\n", get_path_buffer()); - pop_path_buffer(save); - return; - } - if (flags.recurse && !rm_dir()) { - pop_path_buffer(save); - return; - } - } - - if (flags.prompt) { - char c; - - fprintf(stderr, "delete '%s'? ", get_path_buffer()); - fflush(stderr); - - c = getchar(); - if (c != 'y' && c != 'Y') { - fprintf(stderr, "Skipping...\n"); - pop_path_buffer(save); - return; - } - } - - if (remove(get_path_buffer()) < 0) { - error_s("failed to delete '%s': %s\n", get_path_buffer(), strerror(errno)); - } else if (flags.verbose) { - output("deleted '%s'\n", get_path_buffer()); - } - - pop_path_buffer(save); -} - -COMMAND(rm) { - - int start, i; - - if (argc < 1) { - global_help(help); - return EXIT_SUCCESS; - } - - flags.prompt = false; - flags.force = false; - flags.verbose = false; - flags.recurse = false; - - start = parse_args(argc, argv, help, short_arg, NULL); - -#ifdef FRENCH - if (streql(argv[0], "-fr")) { - printf("\x1b[94mremoving \x1b[97mthe \x1b[91mfrench \x1b[93m(baguette noises)\x1b[0m\n"); - } -#endif - - for (i = start; i < argc; i++) { - rm_file(argv[i]); - } - - return EXIT_SUCCESS; -} diff --git a/src/commands/tac.c b/src/commands/tac.c deleted file mode 100644 index d188de9..0000000 --- a/src/commands/tac.c +++ /dev/null @@ -1,117 +0,0 @@ -#include "../command.h" - -#include <stdio.h> -#include <stdlib.h> -#include <limits.h> - -static void help(void) { - printf("Usage: tac [FILE]...\n\n"); - printf("Concatenate FILEs and print them in reverse\n"); -} - -static void print_range(FILE* file, int start, int end) { - int len, i; - - len = end - start; - fseek(file, start, SEEK_SET); - - for (i = 0; i < len; i++) { - putchar(getc(file)); - } - - fflush(stdout); -} - -static char stdin_path[PATH_MAX]; - -static FILE* read_stdin (void) { - static bool read; - static FILE* file; - int r; - char c; - - if (read) goto finished; - read = true; - - srand(time(NULL)); - - r = rand() % 1000000; - - sprintf(stdin_path, "/tmp/%d.tac", r); - file = get_file(stdin_path, "w"); - - while((c = getchar()) != EOF) putc(c, file); - fclose(file); - - file = get_file(stdin_path, "r"); - -finished: - return file; -} - -static void parse_file(FILE* file, struct Stack* stack) { - char buf[1024], c; - int read, i; - int total = 1; - - stack_push_int(stack, 0); - rewind(file); - while ((read = fread(buf, 1, 1024, file)) > 0) { - for (i = 0; i < read; i++) { - c = buf[i]; - if (c != '\n') continue; - stack_push_int(stack, total + i); - } - total += read; - } -} - -static void tac_file(FILE* file) { - struct Stack stack; - int last, current; - - stack_init(&stack, 80); - parse_file(file, &stack); - rewind(file); - - if (!stack_pop_int(&stack, &last)) goto cleanup; - - while(stack_pop_int(&stack, ¤t)) { - print_range(file, current, last); - last = current; - } - -cleanup: - - stack_free(&stack); -} - -COMMAND(tac) { - - FILE* in; - int i; - - parse_help(argc, argv, help); - - in = read_stdin(); - - if (argc < 1) { - tac_file(in); - return EXIT_SUCCESS; - } - - for (i = 0; i < argc; i++) { - FILE* file = get_file(argv[i], "r"); - if (file == stdin) { - tac_file(in); - } else { - tac_file(file); - fclose(file); - } - } - - fclose(in); - remove(stdin_path); - - return EXIT_SUCCESS; -} diff --git a/src/commands/tail.c b/src/commands/tail.c deleted file mode 100644 index 07b3d2b..0000000 --- a/src/commands/tail.c +++ /dev/null @@ -1,238 +0,0 @@ -#include "../command.h" - -static struct { - bool lines; - int count; - bool print_headers; - bool dont_print_headers; - bool print_as_grow; - int grow_wait; -} flags; - -static size_t tail_file_lines(FILE* file, unsigned int count, size_t skip) { - - char** ring; - int* ring_len; - int index, read; - unsigned int size, i; - size_t len; - char* line; - - ring = malloc(sizeof(char*) * count); - memset(ring, 0, sizeof(char*) * count); - - ring_len = malloc(sizeof(int) * count); - - index = 0; - size = 0; - - fseek(file, skip, SEEK_SET); - - len = skip; - line = NULL; - - while ((read = getline(&line, &len, file)) != -1) { - - if (ring[index] != NULL) free(ring[index]); - ring[index] = line; - ring_len[index] = read; - - index++; - index %= count; - if (size < count) size++; - - line = NULL; - } - - index += count - size; - index %= count; - - for (i = 0; i < size; i++) { - fwrite(ring[index], ring_len[index], 1, stdout); - free(ring[index]); - index += 1; - index %= count; - } - - free(line); - fclose(file); - free(ring); - free(ring_len); - - return len; -} - -static size_t tail_file_chars(FILE* file, unsigned int count, size_t skip) { - - char* ring; - int index; - unsigned int size, i; - int read, c; - - ring = malloc(sizeof(char) * count); - memset(ring, 0, count); - - index = 0; - size = 0; - - fseek(file, skip, SEEK_SET); - read = skip; - - while((c = getc(file)) != EOF) { - ring[index] = c; - index++; - read++; - index %= count; - if (size < count) size++; - } - - index += count - size; - index %= count; - - for (i = 0; i < size; i++) { - putchar(ring[index]); - index += 1; - index %= count; - } - - fclose(file); - - return read; -} - -static void help(void) { - printf("Usage: tail [OPTIONS] [FILE]...\n\n"); - printf("Print last 10 lines of FILEs (or stdin) to.\n"); - printf("With more than one FILE, precede each with a filename header.\n\n"); - printf("\t-c [+]N[bkm]\tPrint last N bytes\n"); - printf("\t-n N[bkm]\tPrint last N lines\n"); - printf("\t\t\t(b:*512 k:*1024 m:*1024^2)\n"); - printf("\t-q\t\tNever print headers\n"); - printf("\t-v\t\tAlways print headers\n"); - printf("\t-f\t\tPrint data as file grows\n"); - printf("\t-s SECONDS\tWait SECONDS between reads with -f\n"); - exit(EXIT_SUCCESS); -} - -static void print_header(char* path, bool many) { - if (flags.dont_print_headers) return; - if (!many && !flags.print_headers) return; - if (streql("-", path)) { - printf("\n==> standard input <==\n"); - } else { - printf("\n=>> %s <==\n", path); - } -} - -static void tail_file(char* path, bool many) { - - FILE* file; - size_t skip; - - file = get_file(path, "r"); - print_header(path, many); - - skip = 0; - while (true) { - if (flags.lines) { - skip = tail_file_lines(file, flags.count, skip); - } else { - skip = tail_file_chars(file, flags.count, skip); - } - if (!flags.print_as_grow) break; - sleep(flags.grow_wait); - get_file(path, "r"); - }; -} - -static int short_arg(char c, char* next) { - switch (c) { - case 'c': { - long int bkm; - - flags.lines = false; - - check_arg(next); - bkm = get_blkm(next); - - if (bkm < 1) { - error("bkm cannot be less than 1"); - } - - flags.count = bkm; - return ARG_USED; - } - case 'n': { - long int bkm; - - flags.lines = true; - - check_arg(next); - bkm = get_blkm(next); - - if (bkm < 1) { - error("bkm cannot be less than 1"); - } - - flags.count = bkm; - return ARG_USED; - } - case 'q': - flags.dont_print_headers = true; - break; - case 'v': - flags.print_headers = true; - break; - case 'f': - flags.print_as_grow = true; - break; - case 's': { - long int sec; - - check_arg(next); - sec = get_number(next); - - if (sec < 1) { - error("wait seconds cannot be less than 1"); - } - - flags.grow_wait = sec; - return ARG_USED; - } - default: - return ARG_INVALID; - } - return ARG_UNUSED; -} - -COMMAND(tail) { - - int start, count, i; - - flags.count = 10; - flags.dont_print_headers = false; - flags.print_headers = false; - flags.lines = true; - flags.print_as_grow = false; - flags.grow_wait = 10; - - start = parse_args(argc, argv, help, short_arg, NULL); - - count = argc - start; - - if (count < 1) { - tail_file_lines(stdin, 10, 0); - return EXIT_SUCCESS; - } - - if (count == 1) { - tail_file(argv[start], false); - return EXIT_SUCCESS; - } - - for (i = 0; i < count; i++) { - tail_file(argv[start + i], true); - } - - return EXIT_SUCCESS; -} diff --git a/src/commands/tee.c b/src/commands/tee.c deleted file mode 100644 index b9b31be..0000000 --- a/src/commands/tee.c +++ /dev/null @@ -1,81 +0,0 @@ -#include "../command.h" - -#include <signal.h> - -static struct { - bool append; - bool handle_sigint; -} flags; - -static void help(void) { - printf("Usage: tee [-ai] [FILE]...\n\n"); - printf("Copy stdin to each FILE, and also to stdout\n\n"); - printf("\t-a Append to the given FILEs, don't overwrite\n"); - printf("\t-i Ignore interrupt signals (SIGINT)\n"); - exit(EXIT_SUCCESS); -} - -static void handle(int dummy){UNUSED(dummy);} - -static void run_tee(int file_count, FILE** files) { - char c; - int i; - - while((c = getchar()) != EOF) { - int i; - for (i = 0; i < file_count; i++) { - fwrite(&c, 1, 1, files[i]); - fflush(files[i]); - } - putchar(c); - } - - for (i = 0; i < file_count; i++) { - fclose(files[i]); - } -} - -static int short_arg(char c, char* next) { - UNUSED(next); - switch (c) { - case 'a': - flags.append = true; - break; - case 'i': - flags.handle_sigint = true; - break; - default: - return ARG_INVALID; - } - return ARG_UNUSED; -} - -COMMAND(tee) { - - int start, i; - FILE** files; - - flags.append = false; - flags.handle_sigint = false; - - start = parse_args(argc, argv, help, short_arg, NULL); - - if (flags.handle_sigint) { - signal(SIGINT, handle); - } - - if (argc - start < 1) { - run_tee(0, NULL); - return EXIT_SUCCESS; - } - - files = malloc(sizeof(FILE*) * (argc - start)); - - for (i = start; i < argc; i++) { - FILE* file = get_file(argv[i], flags.append ? "a" : "w"); - files[i - start] = file; - } - - run_tee(argc - start, files); - return EXIT_SUCCESS; -} diff --git a/src/commands/wc.c b/src/commands/wc.c deleted file mode 100644 index d8905a5..0000000 --- a/src/commands/wc.c +++ /dev/null @@ -1,159 +0,0 @@ -#include "../command.h" - -#include <ctype.h> - -static struct { - bool newlines; - bool words; - bool characters; - bool bytes; - bool longest_line; - bool has_flags; -} flags; - -static int lines = 0; -static int words = 0; -static int chars = 0; -static int bytes = 0; -static int logst = 0; - -static void list(int l, int w, int c, int b, int lg) { - if (flags.newlines) { - printf("\t%d", l); - } - if (flags.words) { - printf("\t%d", w); - } - if (flags.characters) { - printf("\t%d", c); - } - if (flags.bytes) { - printf("\t%d", b); - } - if (flags.longest_line) { - printf("\t%d", lg); - } -} - -#define BS 1024 - -static bool is_delimiter(char c) { - return c == ' ' || c == '\t' || c == '\n'; -} - -static void run_wc(FILE* file) { - int l = 0, w = 0, c = 0, b = 0, lg = 0; - - bool in_word = false; - int current_length = 0; - - int read; - char buf[BS]; - while ((read = fread(buf, 1, 1024, file)) > 0) { - int i; - for (i = 0; i < read; i++) { - char ch = buf[i]; - b++; - if (ch == '\n') { - l++; - lg = lg > current_length ? lg : current_length; - current_length = 0; - } else { - current_length++; - } - if (isprint(ch) || is_delimiter(ch)) c++; - if (in_word && is_delimiter(ch)) { - in_word = false; - w++; - } else if (!in_word && !is_delimiter(ch) && isprint(ch)) { - in_word = true; - } - } - } - if (in_word) w++; - lg = lg > current_length ? lg : current_length; - list(l, w, c, b, lg); - lines += l; - words += w; - chars += c; - bytes += b; - logst += lg; - if (file != stdin) - fclose(file); -} - -static void help(void) { - printf("Usage: wc [-cmlwL] [FILE]...\n\n"); - printf("Count lines, words, and bytes for FILEs (or stdin)\n\n"); - printf("\t-c Count bytes\n"); - printf("\t-m Count characters\n"); - printf("\t-l Count newlines\n"); - printf("\t-w Count words\n"); - printf("\t-L Print longest line length\n"); - exit(EXIT_SUCCESS); -} - -static int short_arg(char c, char* next) { - UNUSED(next); - switch (c) { - case 'c': - flags.bytes = true; - break; - case 'm': - flags.characters = true; - break; - case 'l': - flags.newlines = true; - break; - case 'w': - flags.words = true; - break; - case 'L': - flags.longest_line = true; - break; - default: - return ARG_INVALID; - } - flags.has_flags = true; - return ARG_UNUSED; -} - -COMMAND(wc) { - - int start, i; - - flags.newlines = false; - flags.words = false; - flags.characters = false; - flags.bytes = false; - flags.longest_line = false; - flags.has_flags = false; - - - start = parse_args(argc, argv, help, short_arg, NULL); - - if (!flags.has_flags) { - flags.newlines = true; - flags.words = true; - flags.characters = true; - } - - if (argc - start < 1) { - run_wc(stdin); - printf("\n"); - return EXIT_SUCCESS; - } - - for (i = start; i < argc; i++) { - FILE* file = get_file(argv[i], "r"); - run_wc(file); - printf("\t%s\n", argv[i]); - } - - if (argc - start > 1) { - list(lines, words, chars, bytes, logst); - printf("\ttotal\n"); - } - - return EXIT_SUCCESS; -} diff --git a/src/commands/whoami.c b/src/commands/whoami.c deleted file mode 100644 index 7fd7c85..0000000 --- a/src/commands/whoami.c +++ /dev/null @@ -1,27 +0,0 @@ -#include "../command.h" - -#include <pwd.h> - -static void help(void) { - printf("Usage: whoami\n\n"); - printf("Print the username associated with the current effective user id\n"); - exit(EXIT_SUCCESS); -} - -COMMAND(whoami) { - - uid_t usr; - struct passwd* passwd; - - parse_help(argc, argv, help); - - usr = getuid(); - passwd = getpwuid(usr); - - if (passwd == NULL) { - printf("\x1b[1;91myou do not exist.\n"); - } else { - printf("%s\n", passwd->pw_name); - } - return EXIT_SUCCESS; -} diff --git a/src/commands/xargs.c b/src/commands/xargs.c deleted file mode 100644 index 3008c3c..0000000 --- a/src/commands/xargs.c +++ /dev/null @@ -1,187 +0,0 @@ -#include "../command.h" -#include <stdio.h> -#include <stdlib.h> - -static struct { - bool null_seperated; - bool ignore_empty; - bool print_command; - bool prompt_command; - int max_args; - FILE* file; -} flags; - -static void help(void) { - printf("Usage: xargs [OPTIONS] [PROG ARGS]\n\n"); - printf("Run PROG on every item given by stdin\n\n"); - printf("\t-0\tInput is separated by NULs\n"); - printf("\t-a FILE\tRead from FILE instead of stdin\n"); - printf("\t-r\tDon't run command if input is empty\n"); - printf("\t-t\tPrint the command on stderr before execution\n"); - printf("\t-p\tAsk user whether to run each command\n"); - printf("\t-n N\tPass no more than N args to PROG\n"); -} - -static int short_arg(char c, char* next) { - UNUSED(next); - - switch (c) { - case '0': - flags.null_seperated = true; - break; - case 'a': - check_arg(next); - flags.file = get_file(next, "r"); - return ARG_USED; - case 'r': - flags.ignore_empty = true; - break; - case 't': - flags.print_command = true; - break; - case 'p': - flags.prompt_command = true; - break; - case 'n': { - long int n; - - check_arg(next); - n = get_number(next); - - if (n < 1) { - error("max arg count must be at least 1"); - } - - flags.max_args = n; - return ARG_USED; - } - default: - return ARG_INVALID; - } - return ARG_UNUSED; -} - -char* read_next(FILE* file, int arg_count) { - - int size, capacity; - char* buf; - char c; - - if (flags.max_args != -1 && arg_count == flags.max_args) return NULL; - - size = 0; - capacity = 8; - buf = malloc(sizeof(char) * capacity); - - while(c = getc(file), true) { - if (c == EOF && size == 0) { - free(buf); - return NULL; - } - - if (size == capacity) { - capacity *= 2; - buf = realloc(buf, sizeof(char) * capacity); - } - - if (c == '\0' || c == EOF || (!flags.null_seperated && c == '\n')) { - buf[size++] = '\0'; - return buf; - } else { - buf[size++] = c; - } - } -} - -void read_args(FILE* file, char*** args, int* size, int* capacity) { - char* arg; - static int read = 0; - while (arg = read_next(file, read), true) { - if (*size == *capacity) { - *capacity *= 2; - *args = realloc(*args, sizeof(char*) * *capacity); - } - (*args)[(*size)++] = arg; - read++; - if (arg == NULL) break; - } -} - -COMMAND(xargs) { - - int start, arg_start, arg_on_stack_count; - int size, capacity, i; - char* command; - char** args; - - flags.null_seperated = false; - flags.ignore_empty = false; - flags.print_command = false; - flags.print_command = false; - flags.max_args = -1; - flags.file = stdin; - - start = parse_args(argc, argv, help, short_arg, NULL); - - if (start >= argc) { - command = "echo"; - } else { - command = argv[start]; - } - - arg_start = start + 1; - - if (arg_start >= argc) { - arg_on_stack_count = 0; - arg_start = argc - 1; - } else { - arg_on_stack_count = argc - arg_start; - } - - size = arg_on_stack_count + 1; - capacity = size + 8; - - args = malloc(sizeof(char*) * capacity); - args[0] = command; - memcpy(&args[1], &argv[arg_start], arg_on_stack_count * sizeof(char*)); - read_args(flags.file, &args, &size, &capacity); - - if (flags.ignore_empty && size < 2) goto cleanup; - - if (flags.prompt_command || flags.print_command) { - for (i = 0; i < size - 1; i++) { - fprintf(stderr, "%s ", args[i]); - } - fprintf(stderr, "\b\n"); - } - - if (flags.prompt_command) { - FILE* in; - char c; - - fprintf(stderr, "Run command? "); - fflush(stderr); - - in = get_tty_stream("r"); - c = getc(in); - fclose(in); - - if (c != 'y' && c != 'Y') { - fprintf(stderr, "Skipping...\n"); - goto cleanup; - } - } - - if (execvp(command, args) == -1) { - error("error: failed to execute command: %s", strerror(errno)); - } - -cleanup: - - for (i = arg_on_stack_count + 1; i < size - 1; i++) { - free(args[i]); - } - fclose(flags.file); - - return EXIT_SUCCESS; -} diff --git a/src/commands/yes.c b/src/commands/yes.c deleted file mode 100644 index 6a44789..0000000 --- a/src/commands/yes.c +++ /dev/null @@ -1,26 +0,0 @@ -#include "../command.h" - -static void help(void) { - printf("Usage: yes [STRING]\n\n"); - printf("Repeatedly output a line with all specified STRING(s), or 'y'.\n"); -} - -COMMAND(yes) { - const char* repeat; - int i; - - parse_help(argc, argv, help); - - if (argc == 0) { - repeat = "y"; - } else { - repeat = argv[0]; - for (i = 1; i < argc; i++) { - *(argv[i]-1) = ' '; - } - } - - while (true) { - printf("%s\n", repeat); - } -} |