summaryrefslogtreecommitdiff
path: root/src/commands
diff options
context:
space:
mode:
authorTyler Murphy <tylerm@tylerm.dev>2023-05-06 00:39:44 -0400
committerTyler Murphy <tylerm@tylerm.dev>2023-05-06 00:39:44 -0400
commitd8f2c10b7108fff6b7e437291093a1cadc15ab9f (patch)
tree3fc50a19d6fbb9c94a8fe147cd2a6c4ba7f59b8d /src/commands
parentansii c (diff)
downloadlazysphere-d8f2c10b7108fff6b7e437291093a1cadc15ab9f.tar.gz
lazysphere-d8f2c10b7108fff6b7e437291093a1cadc15ab9f.tar.bz2
lazysphere-d8f2c10b7108fff6b7e437291093a1cadc15ab9f.zip
refactor
Diffstat (limited to 'src/commands')
-rw-r--r--src/commands/cat.c140
-rw-r--r--src/commands/cp.c240
-rw-r--r--src/commands/dd.c60
-rw-r--r--src/commands/echo.c104
-rw-r--r--src/commands/ed.c917
-rw-r--r--src/commands/grep.c265
-rw-r--r--src/commands/groups.c42
-rw-r--r--src/commands/head.c138
-rw-r--r--src/commands/id.c53
-rw-r--r--src/commands/ls.c552
-rw-r--r--src/commands/mkdir.c65
-rw-r--r--src/commands/mv.c116
-rw-r--r--src/commands/printf.c141
-rw-r--r--src/commands/rm.c136
-rw-r--r--src/commands/tac.c117
-rw-r--r--src/commands/tail.c238
-rw-r--r--src/commands/tee.c81
-rw-r--r--src/commands/wc.c159
-rw-r--r--src/commands/whoami.c27
-rw-r--r--src/commands/xargs.c187
-rw-r--r--src/commands/yes.c26
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, &regex, 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, &regex, 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, &current)) {
- 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);
- }
-}