summaryrefslogtreecommitdiff
path: root/src
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
parentansii c (diff)
downloadlazysphere-d8f2c10b7108fff6b7e437291093a1cadc15ab9f.tar.gz
lazysphere-d8f2c10b7108fff6b7e437291093a1cadc15ab9f.tar.bz2
lazysphere-d8f2c10b7108fff6b7e437291093a1cadc15ab9f.zip
refactor
Diffstat (limited to 'src')
-rw-r--r--src/command.h19
-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
-rw-r--r--src/main.c10
-rw-r--r--src/util/regex.c528
-rw-r--r--src/util/regex.h65
-rw-r--r--src/util/shared.c372
-rw-r--r--src/util/shared.h86
-rw-r--r--src/util/stack.c43
-rw-r--r--src/util/stack.h22
29 files changed, 5 insertions, 4944 deletions
diff --git a/src/command.h b/src/command.h
index cca2877..87cc749 100644
--- a/src/command.h
+++ b/src/command.h
@@ -1,32 +1,17 @@
#ifndef COMMAND_H
#define COMMAND_H
-#include "util/shared.h"
-#include "util/stack.h"
-#include "util/regex.h"
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <errno.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-
#define ARGUMENTS int argc, char** argv
#define NEXT_ARGS argc - 1, &argv[1]
#define COMMAND(name) int name (ARGUMENTS)
-#define COMMAND_EMPTY(name) int name (void)
COMMAND(dd);
COMMAND(cat);
COMMAND(yes);
COMMAND(echo);
COMMAND(print);
-COMMAND_EMPTY(groups);
-COMMAND_EMPTY(user_id);
+COMMAND(groups);
+COMMAND(user_id);
COMMAND(ls);
COMMAND(tail);
COMMAND(head);
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);
- }
-}
diff --git a/src/main.c b/src/main.c
index 1977e17..ad64b10 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,12 +1,8 @@
-#include "util/shared.h"
#include "command.h"
+#include "lslib.h"
-#include <stdint.h>
#include <stdlib.h>
#include <string.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/types.h>
char* cmd;
@@ -51,9 +47,9 @@ int main (ARGUMENTS) {
} else if (streql(cmd, "printf")) {
return print(NEXT_ARGS);
} else if (streql(cmd, "groups")) {
- return groups();
+ return groups(NEXT_ARGS);
} else if (streql(cmd, "id")) {
- return user_id();
+ return user_id(NEXT_ARGS);
} else if (streql(cmd, "ls") || streql(cmd, "dir")) {
return ls(NEXT_ARGS);
} else if (streql(cmd, "lsd")) {
diff --git a/src/util/regex.c b/src/util/regex.c
deleted file mode 100644
index 0e0dc52..0000000
--- a/src/util/regex.c
+++ /dev/null
@@ -1,528 +0,0 @@
-/*
- *
- * Mini regex-module inspired by Rob Pike's regex code described in:
- *
- * http://www.cs.princeton.edu/courses/archive/spr09/cos333/beautiful.html
- *
- *
- *
- * Supports:
- * ---------
- * '.' Dot, matches any character
- * '^' Start anchor, matches beginning of string
- * '$' End anchor, matches end of string
- * '*' Asterisk, match zero or more (greedy)
- * '+' Plus, match one or more (greedy)
- * '?' Question, match zero or one (non-greedy)
- * '[abc]' Character class, match if one of {'a', 'b', 'c'}
- * '[^abc]' Inverted class, match if NOT one of {'a', 'b', 'c'} -- NOTE: feature is currently broken!
- * '[a-zA-Z]' Character ranges, the character set of the ranges { a-z | A-Z }
- * '\s' Whitespace, \t \f \r \n \v and spaces
- * '\S' Non-whitespace
- * '\w' Alphanumeric, [a-zA-Z0-9_]
- * '\W' Non-alphanumeric
- * '\d' Digits, [0-9]
- * '\D' Non-digits
- *
- *
- */
-
-
-
-#include "regex.h"
-#include <stdio.h>
-#include <ctype.h>
-
-/* Definitions: */
-
-#define MAX_REGEXP_OBJECTS 30 /* Max number of regex symbols in expression. */
-#define MAX_CHAR_CLASS_LEN 40 /* Max length of character-class buffer in. */
-
-
-enum { UNUSED, DOT, BEGIN, END, QUESTIONMARK, STAR, PLUS, CHAR, CHAR_CLASS, INV_CHAR_CLASS, DIGIT, NOT_DIGIT, ALPHA, NOT_ALPHA, WHITESPACE, NOT_WHITESPACE};
-
-typedef struct regex_t
-{
- unsigned char type; /* CHAR, STAR, etc. */
- union
- {
- unsigned char ch; /* the character itself */
- unsigned char* ccl; /* OR a pointer to characters in class */
- } u;
-} regex_t;
-
-
-
-/* Private function declarations: */
-static int matchpattern(regex_t* pattern, const char* text, int* matchlength);
-static int matchcharclass(char c, const char* str);
-static int matchstar(regex_t p, regex_t* pattern, const char* text, int* matchlength);
-static int matchplus(regex_t p, regex_t* pattern, const char* text, int* matchlength);
-static int matchone(regex_t p, char c);
-static int matchdigit(char c);
-static int matchalpha(char c);
-static int matchwhitespace(char c);
-static int matchmetachar(char c, const char* str);
-static int matchrange(char c, const char* str);
-static int matchdot(char c);
-static int ismetachar(char c);
-
-
-
-/* Public functions: */
-int re_match(const char* pattern, const char* text, int* matchlength)
-{
- return re_matchp(re_compile(pattern), text, matchlength);
-}
-
-int re_matchp(re_t pattern, const char* text, int* matchlength)
-{
- *matchlength = 0;
- if (pattern != 0)
- {
- if (pattern[0].type == BEGIN)
- {
- return ((matchpattern(&pattern[1], text, matchlength)) ? 0 : -1);
- }
- else
- {
- int idx = -1;
-
- do
- {
- idx += 1;
-
- if (matchpattern(pattern, text, matchlength))
- {
- if (text[0] == '\0')
- return -1;
-
- return idx;
- }
- }
- while (*text++ != '\0');
- }
- }
- return -1;
-}
-
-re_t re_compile(const char* pattern)
-{
- /* The sizes of the two static arrays below substantiates the static RAM usage of this module.
- MAX_REGEXP_OBJECTS is the max number of symbols in the expression.
- MAX_CHAR_CLASS_LEN determines the size of buffer for chars in all char-classes in the expression. */
- static regex_t re_compiled[MAX_REGEXP_OBJECTS];
- static unsigned char ccl_buf[MAX_CHAR_CLASS_LEN];
- int ccl_bufidx = 1;
-
- char c; /* current char in pattern */
- int i = 0; /* index into pattern */
- int j = 0; /* index into re_compiled */
-
- while (pattern[i] != '\0' && (j+1 < MAX_REGEXP_OBJECTS))
- {
- c = pattern[i];
-
- switch (c)
- {
- /* Meta-characters: */
- case '^': { re_compiled[j].type = BEGIN; } break;
- case '$': { re_compiled[j].type = END; } break;
- case '.': { re_compiled[j].type = DOT; } break;
- case '*': { re_compiled[j].type = STAR; } break;
- case '+': { re_compiled[j].type = PLUS; } break;
- case '?': { re_compiled[j].type = QUESTIONMARK; } break;
-/* case '|': { re_compiled[j].type = BRANCH; } break; <-- not working properly */
-
- /* Escaped character-classes (\s \w ...): */
- case '\\':
- {
- if (pattern[i+1] != '\0')
- {
- /* Skip the escape-char '\\' */
- i += 1;
- /* ... and check the next */
- switch (pattern[i])
- {
- /* Meta-character: */
- case 'd': { re_compiled[j].type = DIGIT; } break;
- case 'D': { re_compiled[j].type = NOT_DIGIT; } break;
- case 'w': { re_compiled[j].type = ALPHA; } break;
- case 'W': { re_compiled[j].type = NOT_ALPHA; } break;
- case 's': { re_compiled[j].type = WHITESPACE; } break;
- case 'S': { re_compiled[j].type = NOT_WHITESPACE; } break;
-
- /* Escaped character, e.g. '.' or '$' */
- default:
- {
- re_compiled[j].type = CHAR;
- re_compiled[j].u.ch = pattern[i];
- } break;
- }
- }
- /* '\\' as last char in pattern -> invalid regular expression. */
-/*
- else
- {
- re_compiled[j].type = CHAR;
- re_compiled[j].ch = pattern[i];
- }
-*/
- } break;
-
- /* Character class: */
- case '[':
- {
- /* Remember where the char-buffer starts. */
- int buf_begin = ccl_bufidx;
-
- /* Look-ahead to determine if negated */
- if (pattern[i+1] == '^')
- {
- re_compiled[j].type = INV_CHAR_CLASS;
- i += 1; /* Increment i to avoid including '^' in the char-buffer */
- if (pattern[i+1] == 0) /* incomplete pattern, missing non-zero char after '^' */
- {
- return 0;
- }
- }
- else
- {
- re_compiled[j].type = CHAR_CLASS;
- }
-
- /* Copy characters inside [..] to buffer */
- while ( (pattern[++i] != ']')
- && (pattern[i] != '\0')) /* Missing ] */
- {
- if (pattern[i] == '\\')
- {
- if (ccl_bufidx >= MAX_CHAR_CLASS_LEN - 1)
- {
- /* fputs("exceeded internal buffer!\n", stderr); */
- return 0;
- }
- if (pattern[i+1] == 0) /* incomplete pattern, missing non-zero char after '\\' */
- {
- return 0;
- }
- ccl_buf[ccl_bufidx++] = pattern[i++];
- }
- else if (ccl_bufidx >= MAX_CHAR_CLASS_LEN)
- {
- /* fputs("exceeded internal buffer!\n", stderr); */
- return 0;
- }
- ccl_buf[ccl_bufidx++] = pattern[i];
- }
- if (ccl_bufidx >= MAX_CHAR_CLASS_LEN)
- {
- /* Catches cases such as [00000000000000000000000000000000000000][ */
- /* fputs("exceeded internal buffer!\n", stderr); */
- return 0;
- }
- /* Null-terminate string end */
- ccl_buf[ccl_bufidx++] = 0;
- re_compiled[j].u.ccl = &ccl_buf[buf_begin];
- } break;
-
- /* Other characters: */
- default:
- {
- re_compiled[j].type = CHAR;
- re_compiled[j].u.ch = c;
- } break;
- }
- /* no buffer-out-of-bounds access on invalid patterns - see https://github.com/kokke/tiny-regex-c/commit/1a279e04014b70b0695fba559a7c05d55e6ee90b */
- if (pattern[i] == 0)
- {
- return 0;
- }
-
- i += 1;
- j += 1;
- }
- /* 'UNUSED' is a sentinel used to indicate end-of-pattern */
- re_compiled[j].type = UNUSED;
-
- return (re_t) re_compiled;
-}
-
-void re_print(regex_t* pattern)
-{
- const char* types[] = { "UNUSED", "DOT", "BEGIN", "END", "QUESTIONMARK", "STAR", "PLUS", "CHAR", "CHAR_CLASS", "INV_CHAR_CLASS", "DIGIT", "NOT_DIGIT", "ALPHA", "NOT_ALPHA", "WHITESPACE", "NOT_WHITESPACE", "BRANCH" };
-
- int i;
- int j;
- char c;
- for (i = 0; i < MAX_REGEXP_OBJECTS; ++i)
- {
- if (pattern[i].type == UNUSED)
- {
- break;
- }
-
- printf("type: %s", types[pattern[i].type]);
- if (pattern[i].type == CHAR_CLASS || pattern[i].type == INV_CHAR_CLASS)
- {
- printf(" [");
- for (j = 0; j < MAX_CHAR_CLASS_LEN; ++j)
- {
- c = pattern[i].u.ccl[j];
- if ((c == '\0') || (c == ']'))
- {
- break;
- }
- printf("%c", c);
- }
- printf("]");
- }
- else if (pattern[i].type == CHAR)
- {
- printf(" '%c'", pattern[i].u.ch);
- }
- printf("\n");
- }
-}
-
-
-
-/* Private functions: */
-static int matchdigit(char c)
-{
- return isdigit(c);
-}
-static int matchalpha(char c)
-{
- return isalpha(c);
-}
-static int matchwhitespace(char c)
-{
- return isspace(c);
-}
-static int matchalphanum(char c)
-{
- return ((c == '_') || matchalpha(c) || matchdigit(c));
-}
-static int matchrange(char c, const char* str)
-{
- return ( (c != '-')
- && (str[0] != '\0')
- && (str[0] != '-')
- && (str[1] == '-')
- && (str[2] != '\0')
- && ( (c >= str[0])
- && (c <= str[2])));
-}
-static int matchdot(char c)
-{
-#if defined(RE_DOT_MATCHES_NEWLINE) && (RE_DOT_MATCHES_NEWLINE == 1)
- (void)c;
- return 1;
-#else
- return c != '\n' && c != '\r';
-#endif
-}
-static int ismetachar(char c)
-{
- return ((c == 's') || (c == 'S') || (c == 'w') || (c == 'W') || (c == 'd') || (c == 'D'));
-}
-
-static int matchmetachar(char c, const char* str)
-{
- switch (str[0])
- {
- case 'd': return matchdigit(c);
- case 'D': return !matchdigit(c);
- case 'w': return matchalphanum(c);
- case 'W': return !matchalphanum(c);
- case 's': return matchwhitespace(c);
- case 'S': return !matchwhitespace(c);
- default: return (c == str[0]);
- }
-}
-
-static int matchcharclass(char c, const char* str)
-{
- do
- {
- if (matchrange(c, str))
- {
- return 1;
- }
- else if (str[0] == '\\')
- {
- /* Escape-char: increment str-ptr and match on next char */
- str += 1;
- if (matchmetachar(c, str))
- {
- return 1;
- }
- else if ((c == str[0]) && !ismetachar(c))
- {
- return 1;
- }
- }
- else if (c == str[0])
- {
- if (c == '-')
- {
- return ((str[-1] == '\0') || (str[1] == '\0'));
- }
- else
- {
- return 1;
- }
- }
- }
- while (*str++ != '\0');
-
- return 0;
-}
-
-static int matchone(regex_t p, char c)
-{
- switch (p.type)
- {
- case DOT: return matchdot(c);
- case CHAR_CLASS: return matchcharclass(c, (const char*)p.u.ccl);
- case INV_CHAR_CLASS: return !matchcharclass(c, (const char*)p.u.ccl);
- case DIGIT: return matchdigit(c);
- case NOT_DIGIT: return !matchdigit(c);
- case ALPHA: return matchalphanum(c);
- case NOT_ALPHA: return !matchalphanum(c);
- case WHITESPACE: return matchwhitespace(c);
- case NOT_WHITESPACE: return !matchwhitespace(c);
- default: return (p.u.ch == c);
- }
-}
-
-static int matchstar(regex_t p, regex_t* pattern, const char* text, int* matchlength)
-{
- int prelen = *matchlength;
- const char* prepoint = text;
- while ((text[0] != '\0') && matchone(p, *text))
- {
- text++;
- (*matchlength)++;
- }
- while (text >= prepoint)
- {
- if (matchpattern(pattern, text--, matchlength))
- return 1;
- (*matchlength)--;
- }
-
- *matchlength = prelen;
- return 0;
-}
-
-static int matchplus(regex_t p, regex_t* pattern, const char* text, int* matchlength)
-{
- const char* prepoint = text;
- while ((text[0] != '\0') && matchone(p, *text))
- {
- text++;
- (*matchlength)++;
- }
- while (text > prepoint)
- {
- if (matchpattern(pattern, text--, matchlength))
- return 1;
- (*matchlength)--;
- }
-
- return 0;
-}
-
-static int matchquestion(regex_t p, regex_t* pattern, const char* text, int* matchlength)
-{
- if (p.type == UNUSED)
- return 1;
- if (matchpattern(pattern, text, matchlength))
- return 1;
- if (*text && matchone(p, *text++))
- {
- if (matchpattern(pattern, text, matchlength))
- {
- (*matchlength)++;
- return 1;
- }
- }
- return 0;
-}
-
-
-#if 0
-
-/* Recursive matching */
-static int matchpattern(regex_t* pattern, const char* text, int *matchlength)
-{
- int pre = *matchlength;
- if ((pattern[0].type == UNUSED) || (pattern[1].type == QUESTIONMARK))
- {
- return matchquestion(pattern[1], &pattern[2], text, matchlength);
- }
- else if (pattern[1].type == STAR)
- {
- return matchstar(pattern[0], &pattern[2], text, matchlength);
- }
- else if (pattern[1].type == PLUS)
- {
- return matchplus(pattern[0], &pattern[2], text, matchlength);
- }
- else if ((pattern[0].type == END) && pattern[1].type == UNUSED)
- {
- return text[0] == '\0';
- }
- else if ((text[0] != '\0') && matchone(pattern[0], text[0]))
- {
- (*matchlength)++;
- return matchpattern(&pattern[1], text+1);
- }
- else
- {
- *matchlength = pre;
- return 0;
- }
-}
-
-#else
-
-/* Iterative matching */
-static int matchpattern(regex_t* pattern, const char* text, int* matchlength)
-{
- int pre = *matchlength;
- do
- {
- if ((pattern[0].type == UNUSED) || (pattern[1].type == QUESTIONMARK))
- {
- return matchquestion(pattern[0], &pattern[2], text, matchlength);
- }
- else if (pattern[1].type == STAR)
- {
- return matchstar(pattern[0], &pattern[2], text, matchlength);
- }
- else if (pattern[1].type == PLUS)
- {
- return matchplus(pattern[0], &pattern[2], text, matchlength);
- }
- else if ((pattern[0].type == END) && pattern[1].type == UNUSED)
- {
- return (text[0] == '\0');
- }
-/* Branching is not working properly
- else if (pattern[1].type == BRANCH)
- {
- return (matchpattern(pattern, text) || matchpattern(&pattern[2], text));
- }
-*/
- (*matchlength)++;
- }
- while ((text[0] != '\0') && matchone(*pattern++, *text++));
-
- *matchlength = pre;
- return 0;
-}
-
-#endif
diff --git a/src/util/regex.h b/src/util/regex.h
deleted file mode 100644
index 69facc6..0000000
--- a/src/util/regex.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- *
- * Mini regex-module inspired by Rob Pike's regex code described in:
- *
- * http://www.cs.princeton.edu/courses/archive/spr09/cos333/beautiful.html
- *
- *
- *
- * Supports:
- * ---------
- * '.' Dot, matches any character
- * '^' Start anchor, matches beginning of string
- * '$' End anchor, matches end of string
- * '*' Asterisk, match zero or more (greedy)
- * '+' Plus, match one or more (greedy)
- * '?' Question, match zero or one (non-greedy)
- * '[abc]' Character class, match if one of {'a', 'b', 'c'}
- * '[^abc]' Inverted class, match if NOT one of {'a', 'b', 'c'} -- NOTE: feature is currently broken!
- * '[a-zA-Z]' Character ranges, the character set of the ranges { a-z | A-Z }
- * '\s' Whitespace, \t \f \r \n \v and spaces
- * '\S' Non-whitespace
- * '\w' Alphanumeric, [a-zA-Z0-9_]
- * '\W' Non-alphanumeric
- * '\d' Digits, [0-9]
- * '\D' Non-digits
- *
- *
- */
-
-#ifndef _TINY_REGEX_C
-#define _TINY_REGEX_C
-
-
-#ifndef RE_DOT_MATCHES_NEWLINE
-/* Define to 0 if you DON'T want '.' to match '\r' + '\n' */
-#define RE_DOT_MATCHES_NEWLINE 1
-#endif
-
-#ifdef __cplusplus
-extern "C"{
-#endif
-
-
-
-/* Typedef'd pointer to get abstract datatype. */
-typedef struct regex_t* re_t;
-
-
-/* Compile regex string pattern to a regex_t-array. */
-re_t re_compile(const char* pattern);
-
-
-/* Find matches of the compiled pattern inside text. */
-int re_matchp(re_t pattern, const char* text, int* matchlength);
-
-
-/* Find matches of the txt pattern inside text (will compile automatically first). */
-int re_match(const char* pattern, const char* text, int* matchlength);
-
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* ifndef _TINY_REGEX_C */
diff --git a/src/util/shared.c b/src/util/shared.c
deleted file mode 100644
index 2e0c98a..0000000
--- a/src/util/shared.c
+++ /dev/null
@@ -1,372 +0,0 @@
-#include "shared.h"
-
-#include <ctype.h>
-#include <errno.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <time.h>
-#include <sys/stat.h>
-#include <paths.h>
-
-extern char* cmd;
-
-void error_s(const char *format, ...) {
- va_list list;
- va_start(list, format);
-
- fprintf(stderr, "%s: ", cmd);
- vfprintf(stderr, format, list);
- fprintf(stderr, "\n");
-}
-
-void error(const char *format, ...) {
- va_list list;
- va_start(list, format);
-
- fprintf(stderr, "%s: ", cmd);
- vfprintf(stderr, format, list);
- fprintf(stderr, "\n");
- exit(EXIT_FAILURE);
-}
-
-void output(const char *format, ...) {
- va_list list;
- va_start(list, format);
-
- fprintf(stdout, "%s: ", cmd);
- vfprintf(stdout, format, list);
- fprintf(stdout, "\n");
-}
-
-FILE* get_file_s(const char* path, const char* type) {
- struct stat s;
- FILE* file;
-
- if (streql("-", path) && type[0] == 'r') {
- clearerr(stdin);
- fflush(stdin);
- return stdin;
- }
-
- if (lstat(path, &s) < 0) {
- if (type[0] != 'r') goto read;
- error_s("failed to read %s: %s", path, strerror(errno));
- return NULL;
- }
-
- if (S_ISDIR(s.st_mode)) {
- error_s("%s is a directory", path);
- return NULL;
- }
-
-read:
-
- file = fopen(path, type);
-
- if (file == NULL) {
- error_s("failed to %s file %s: %s", type[0] == 'r' ? "read" : "write", path, strerror(errno));
- }
-
- return file;
-}
-
-FILE* get_file(const char* path, const char* type) {
- FILE* file = get_file_s(path, type);
- if (file == NULL) exit(EXIT_FAILURE);
- return file;
-}
-
-long int get_number(const char* text) {
- char* end;
- long int n = strtol(text, &end, 10);
- if (text == end) {
- error("%s is not a valid number", text);
- }
- return n;
-}
-
-long int get_blkm(const char* text) {
- char* end;
- long int n = strtol(text, &end, 10);
- if (text == end) {
- error("%s is not a valid bkm", text);
- }
- if (*end == '\0') return n;
- switch (*end) {
- case 'K':
- case 'k':
- return n * 1024;
- case 'B':
- case 'b':
- return n * 512;
- case 'M':
- case 'm':
- return n * 1024 * 1204;
- default:
- error("invalid bkm type %c", *end);
- }
-
- /* shouldnt get here anyways */
- return 0;
-}
-
-mode_t get_mode(const char* next) {
- char* end = NULL;
- mode_t mode = (mode_t)strtol(next, &end, 8);
- if (!end) return 0;
- while(isspace(*end)) end++;
- if (*end != '\0' || (unsigned) mode < 010000) {
- error("invalid file mode: `%s`", next);
- }
- return mode;
-}
-
-bool streql(const char* a, const char* b) {
- int n = 0;
-
- if (*a != *b) return false;
-
- while (true) {
- if (*(a+n) != *(b+n)) return false;
- if (*(a+n) == '\0') return true;
- ++n;
- }
-}
-
-bool prefix(const char* pre, const char* str) {
- return strncmp(pre, str, strlen(pre)) == 0;
-}
-
-static char fs_types[5] = {'K','M','G','T','P'};
-void print_file_size(size_t bytes, char buf[5]) {
- int index, n;
- float next;
-
- index = 0;
- next = bytes;
-
- while (true) {
- if (next < 1000) {
- break;
- }
-
- if (index == 5) {
- printf("999P");
- return;
- }
-
- next /= 1024;
- index++;
- }
-
- n = snprintf(buf, 4, "%u", (int)(next+.5));
-
- if (index > 0) {
- buf[n] = (fs_types[index - 1]);
- n++;
- }
-
- buf[n] = '\0';
-}
-
-static char* months[12] =
- {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
-void print_date_time(time_t mills, char buf[13]) {
- struct tm* info;
- int n;
-
- info = localtime(&mills);
- n = snprintf(buf, 5, "%s ", months[info->tm_mon]);
-
- if (info->tm_mday < 10) {
- buf[n] = ' ';
- n++;
- }
-
- snprintf(buf + n, 13 - n, "%d %02d:%02d ", info->tm_mday, info->tm_hour, info->tm_sec);
-}
-
-void print_file_path(char* path) {
- if (streql("-", path)) {
- printf("(standard input)");
- } else {
- printf("%s", path);
- }
-}
-
-#ifndef MAJOR
-#define MAJOR 0
-#endif
-
-#ifndef MINOR
-#define MINOR 0
-#endif
-
-#ifndef PATCH
-#define PATCH 0
-#endif
-
-void check_arg (char* arg) {
- if (arg == NULL) {
- error("expected another argument after option");
- }
-}
-
-void global_help(void (*help)(void)) {
- printf("LazySphere v%d.%d.%d multi-call binary.\n\n", MAJOR, MINOR, PATCH);
- help();
- exit(EXIT_SUCCESS);
-}
-
-void parse_help(int argc, char** argv, void (*help)(void)) {
- int i;
-
- if (argc < 1) return;
-
- for (i = 0; i < argc; i++) {
- if (!prefix("-", argv[i]) || streql("-", argv[i])) break;
- if (help != NULL && streql("--help", argv[i])) global_help(help);
- }
-}
-
-int parse_args(int argc, char** argv, void (*help)(void), int (*short_arg)(char, char*), int (*long_arg)(char*, char*)) {
- int start, i, current;
- char* next_arg;
-
- if (argc < 1) return 0;
-
- start = 0;
- for (i = 0; i < argc; i++) {
-
- if (!prefix("-", argv[i]) || streql("-", argv[i])) break;
- if (help != NULL && streql("--help", argv[i])) global_help(help);
-
- if (i + 1 == argc) {
- next_arg = NULL;
- } else {
- next_arg = argv[i+1];
- }
-
- current = i;
-
- if (prefix("--", argv[i])) {
- int r;
-
- if (long_arg == NULL) {
- goto exit;
- }
-
- r = long_arg(argv[current], next_arg);
-
- if (r == ARG_USED) {
- i++;
- start++;
- } else if (r == ARG_IGNORE) {
- goto exit;
- } else if (r == ARG_INVALID) {
- error("invalid argument %s", argv[current]);
-
- }
- } else {
- size_t j;
- int r;
-
- if (short_arg == NULL) {
- goto exit;
- }
-
- for (j = 1; j < strlen(argv[current]); j++) {
-
- r = short_arg(argv[current][j], next_arg);
-
- if (r == ARG_USED) {
- i++;
- start++;
- } else if (r == ARG_IGNORE) {
- goto exit;
- } else if (r == ARG_INVALID) {
- error("invalid argument -%c", argv[current][j]);
- }
- }
- }
-
- start++;
- }
-
-exit:
-
- return start;
-}
-
-int get_tty (void) {
- int fd = open(_PATH_TTY, O_RDONLY);
- if (fd < 0) error("failed to get tty: %s", strerror(errno));
- return fd;
-}
-
-FILE* get_tty_stream(char* type) {
- int fd = get_tty();
- FILE* file = fdopen(fd, type);
- if (file == NULL) {
- error("failed to open tty stream: %s", strerror(errno));
- }
- return file;
-}
-
-static int push_path_buffer_b(char* buf, int* index, const char* string) {
- int save, string_len;
-
- save = *index;
- if (*index > 1 || (*index == 1 && buf[0] != '/')) {
- buf[(*index)++] = '/';
- }
-
- string_len = strlen(string);
- memcpy(buf + *index, string, string_len + 1);
-
- *index += string_len;
-
- return save;
-}
-
-static void pop_path_buffer_b(char* buf, int* index, int i) {
- *index = i;
- buf[*index] = '\0';
-}
-
-static char path_buffer[PATH_MAX + 1];
-static int path_buffer_index = 0;
-
-char* get_path_buffer(void) {
- return path_buffer;
-}
-
-int push_path_buffer(const char* string) {
- return push_path_buffer_b(path_buffer, &path_buffer_index, string);
-}
-
-void pop_path_buffer(int i) {
- pop_path_buffer_b(path_buffer, &path_buffer_index, i);
-}
-
-static char path_buffer_2[PATH_MAX + 1];
-static int path_buffer_index_2 = 0;
-
-char* get_path_buffer_2(void) {
- return path_buffer_2;
-}
-
-int push_path_buffer_2(const char* string) {
- return push_path_buffer_b(path_buffer_2, &path_buffer_index_2, string);
-}
-
-void pop_path_buffer_2(int i) {
- pop_path_buffer_b(path_buffer_2, &path_buffer_index_2, i);
-}
-
-bool is_dot_dir(const char* path) {
- return streql(path, ".") || streql(path, "..");
-}
diff --git a/src/util/shared.h b/src/util/shared.h
deleted file mode 100644
index a3e6a56..0000000
--- a/src/util/shared.h
+++ /dev/null
@@ -1,86 +0,0 @@
-#ifndef SHARED_H
-#define SHARED_H
-
-#include <stdint.h>
-#include <stdio.h>
-#include <time.h>
-#include <fcntl.h>
-
-#define ANSCII "\x1b["
-#define NEXT ";"
-
-#define RESET "0"
-#define BOLD "1"
-
-#define NORMAL "3"
-#define BACKGROUND "4"
-#define HIGHLIGHT "9"
-
-#define BLACK "0"
-#define RED "1"
-#define GREEN "2"
-#define YELLOW "3"
-#define BLUE "4"
-#define MAGENTA "5"
-#define TURQUOISE "6"
-#define WHITE "7"
-
-#define COLOR "m"
-
-typedef uint8_t bool;
-#define true 1
-#define false 0
-
-enum When {
- YES,
- NO,
- AUTO
-};
-
-__attribute__ ((__format__(printf, 1, 2)))
-void error_s(const char* format, ...);
-
-__attribute__ ((__format__(printf, 1, 2)))
-void error(const char* format, ...);
-
-__attribute__ ((__format__(printf, 1, 2)))
-void output(const char* format, ...);
-
-FILE* get_file_s(const char* path, const char* type);
-FILE* get_file(const char* path, const char* type);
-long int get_number(const char* text);
-long int get_blkm(const char* text);
-mode_t get_mode(const char* next);
-
-bool streql(const char* a, const char* b);
-bool prefix(const char* pre, const char* str);
-
-void print_file_size(size_t bytes, char buf[5]);
-void print_date_time(time_t mills, char buf[13]);
-void print_file_path(char* path);
-
-#define UNUSED(x) (void)(x)
-#define ARG_UNUSED 0
-#define ARG_USED 1
-#define ARG_IGNORE 2
-#define ARG_INVALID 3
-
-void check_arg (char* arg);
-void global_help(void (*help)(void));
-void parse_help (int argc, char** argv, void (*help)(void));
-int parse_args (int argc, char** argv, void (*help)(void), int (*short_arg)(char, char*), int (*long_arg)(char*, char*));
-
-int get_tty(void);
-FILE* get_tty_stream(char* type);
-
-char* get_path_buffer(void);
-int push_path_buffer(const char* string);
-void pop_path_buffer(int i);
-
-char* get_path_buffer_2(void);
-int push_path_buffer_2(const char* string);
-void pop_path_buffer_2(int i);
-
-bool is_dot_dir(const char* path);
-
-#endif
diff --git a/src/util/stack.c b/src/util/stack.c
deleted file mode 100644
index acffc1a..0000000
--- a/src/util/stack.c
+++ /dev/null
@@ -1,43 +0,0 @@
-#include "stack.h"
-
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-void stack_init(struct Stack* stack, size_t size) {
- stack->size = 0;
- stack->capacity = size;
- stack->data = malloc(size);
-}
-
-void stack_push(struct Stack* stack, void* data, size_t len) {
- size_t new_size = stack->size + len;
- if (new_size >= stack->capacity) {
- stack->capacity = new_size * 2;
- stack->data = realloc(stack->data, stack->capacity);
- }
- memcpy((uint8_t*)stack->data + stack->size, data, len);
- stack->size += len;
-}
-
-void* stack_pop(struct Stack* stack, size_t len) {
- if (stack->size < len) return NULL;
- stack->size -= len;
- return (uint8_t*)stack->data + stack->size;
-}
-
-void stack_free(struct Stack *stack) {
- free(stack->data);
-}
-
-void stack_push_int(struct Stack *stack, int value) {
- stack_push(stack, &value, sizeof(int));
-}
-
-bool stack_pop_int(struct Stack *stack, int* value) {
- void* d = stack_pop(stack, sizeof(int));
- if (d == NULL) return false;
- *value = *(int*)(d);
- return true;
-}
diff --git a/src/util/stack.h b/src/util/stack.h
deleted file mode 100644
index 8d6fc80..0000000
--- a/src/util/stack.h
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef STACK_H
-#define STACK_H
-
-#include "shared.h"
-
-#include <stddef.h>
-
-struct Stack {
- size_t size;
- size_t capacity;
- void* data;
-};
-
-void stack_init(struct Stack* stack, size_t size);
-void stack_push(struct Stack* stack, void* data, size_t len);
-void* stack_pop(struct Stack* stack, size_t len);
-void stack_free(struct Stack* stack);
-
-void stack_push_int(struct Stack* stack, int value);
-bool stack_pop_int(struct Stack* stack, int* value);
-
-#endif