summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTyler Murphy <tylerm@tylerm.dev>2023-05-01 00:31:13 -0400
committerTyler Murphy <tylerm@tylerm.dev>2023-05-01 00:31:13 -0400
commit317f7bf35716f7059511f42f1f4aba7d47fcfd01 (patch)
tree2ea2c6ec05eff6bd8a3d139b04834dfb624754b8
parentupdate ed help message to make s commands make more sense (diff)
downloadlazysphere-317f7bf35716f7059511f42f1f4aba7d47fcfd01.tar.gz
lazysphere-317f7bf35716f7059511f42f1f4aba7d47fcfd01.tar.bz2
lazysphere-317f7bf35716f7059511f42f1f4aba7d47fcfd01.zip
tee, whoami, wc
-rw-r--r--readme.md2
-rw-r--r--src/command.h3
-rw-r--r--src/commands/id.c1
-rw-r--r--src/commands/tee.c75
-rw-r--r--src/commands/wc.c161
-rw-r--r--src/commands/whoami.c24
-rw-r--r--src/main.c14
7 files changed, 277 insertions, 3 deletions
diff --git a/readme.md b/readme.md
index 2c02009..50f9067 100644
--- a/readme.md
+++ b/readme.md
@@ -4,7 +4,7 @@
A terrible busybox/gnu coreutils clone.
Currently the only supported commands are:
-`dd`, `cat`, `yes`, `echo`, `printf`, `id`, `groups`, `ls`, `tail`, `head`, `ed`
+`dd`, `cat`, `yes`, `echo`, `printf`, `id`, `groups`, `ls`, `tail`, `head`, `ed`, `tee`, `true`, `false`, `tee`, `whoami`, `wc`
## How to
diff --git a/src/command.h b/src/command.h
index fb1acb3..ab1ccea 100644
--- a/src/command.h
+++ b/src/command.h
@@ -20,3 +20,6 @@ COMMAND(ls);
COMMAND(tail);
COMMAND(head);
COMMAND(ed);
+COMMAND(tee);
+COMMAND(whoami);
+COMMAND(wc);
diff --git a/src/commands/id.c b/src/commands/id.c
index f1790bc..3990dc8 100644
--- a/src/commands/id.c
+++ b/src/commands/id.c
@@ -3,6 +3,7 @@
#include <grp.h>
#include <pwd.h>
#include <unistd.h>
+#include <sys/types.h>
COMMAND_EMPTY(user_id) {
diff --git a/src/commands/tee.c b/src/commands/tee.c
new file mode 100644
index 0000000..224463c
--- /dev/null
+++ b/src/commands/tee.c
@@ -0,0 +1,75 @@
+#include "../command.h"
+
+#include <signal.h>
+#include <stdio.h>
+#include <string.h>
+
+
+static void help() {
+ 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(){}
+
+static void run_tee(int file_count, FILE* files[file_count]) {
+ char c;
+ while((c = getchar()) != EOF) {
+ for (int i = 0; i < file_count; i++) {
+ fwrite(&c, 1, 1, files[i]);
+ fflush(files[i]);
+ }
+ putchar(c);
+ }
+ for (int i = 0; i < file_count; i++) {
+ fclose(files[i]);
+ }
+}
+
+COMMAND(tee) {
+
+ bool append = false;
+ bool handle_sigint = false;
+
+ int start = 0;
+ for (int i = 0; i < argc; i++) {
+ if (!prefix("-", argv[i])) break;
+ if (streql("--help", argv[i])) help();
+
+ start++;
+ for (size_t j = 1; j < strlen(argv[i]); j++) {
+ char o = argv[i][j];
+ switch (o) {
+ case 'a':
+ append = true;
+ break;
+ case 'i':
+ handle_sigint = true;
+ break;
+ default:
+ error("error: unkown option: %c", o);
+ }
+ }
+ }
+
+ if (handle_sigint) {
+ signal(SIGINT, handle);
+ }
+
+ if (argc - start < 1) {
+ run_tee(0, NULL);
+ return EXIT_SUCCESS;
+ }
+
+ FILE* files[argc - start];
+ for (int i = start; i < argc; i++) {
+ FILE* file = get_file(argv[i], 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
new file mode 100644
index 0000000..7132370
--- /dev/null
+++ b/src/commands/wc.c
@@ -0,0 +1,161 @@
+#include "../command.h"
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+struct Flags {
+ bool newlines;
+ bool words;
+ bool characters;
+ bool bytes;
+ bool longest_line;
+};
+
+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, struct Flags* flags) {
+ 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, struct Flags* flags) {
+ 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) {
+ for (int 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, flags);
+ lines += l;
+ words += w;
+ chars += c;
+ bytes += b;
+ logst += lg;
+ if (file != stdin)
+ fclose(file);
+}
+
+static void help() {
+ 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);
+}
+
+COMMAND(wc) {
+ struct Flags flags;
+ flags.newlines = false;
+ flags.words = false;
+ flags.characters = false;
+ flags.bytes = false;
+ flags.longest_line = false;
+
+ bool has_flags = false;
+
+ int start = 0;
+ for (int i = 0; i < argc; i++) {
+ if (!prefix("-", argv[i])) break;
+ if (streql("--help", argv[i])) help();
+
+ start++;
+ for (size_t j = 1; j < strlen(argv[i]); j++) {
+ char c = argv[i][j];
+ 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:
+ error("error: invald option -%c", c);
+ }
+ has_flags = true;
+ }
+ }
+
+ if (!has_flags) {
+ flags.newlines = true;
+ flags.words = true;
+ flags.characters = true;
+ }
+
+ if (argc - start < 1) {
+ run_wc(stdin, &flags);
+ printf("\n");
+ return EXIT_SUCCESS;
+ }
+
+ for (int i = start; i < argc; i++) {
+ FILE* file = get_file(argv[i], "r");
+ run_wc(file, &flags);
+ printf("\t%s\n", argv[i]);
+ }
+
+ if (argc - start > 1) {
+ list(lines, words, chars, bytes, logst, &flags);
+ printf("\ttotal\n");
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/commands/whoami.c b/src/commands/whoami.c
new file mode 100644
index 0000000..efc9bcd
--- /dev/null
+++ b/src/commands/whoami.c
@@ -0,0 +1,24 @@
+#include "../command.h"
+
+#include <pwd.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static void help() {
+ printf("Usage: whoami\n\n");
+ printf("Print the username associated with the current effective user id\n");
+ exit(EXIT_SUCCESS);
+}
+
+COMMAND(whoami) {
+ if (argc > 0 && streql("--help", argv[0])) help();
+
+ uid_t usr = getuid();
+ struct passwd* 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/main.c b/src/main.c
index cd9a81f..d8ee1b4 100644
--- a/src/main.c
+++ b/src/main.c
@@ -20,7 +20,7 @@ int main (ARGUMENTS) {
if (argc < 2) {
printf("usage: lazysphere [function [arguments]...]\n\n");
printf("currently defined functions:\n");
- printf("\tdd, cat, yes, echo, printf, id, groups, ls, tail, head, ed\n");
+ printf("\tdd, cat, yes, echo, printf, id, groups, ls, tail, head, ed, tee, true, false, tee, whoami, wc\n");
return EXIT_SUCCESS;
}
argc--;
@@ -48,7 +48,7 @@ int main (ARGUMENTS) {
return groups();
} else if (streql(cmd, "id")) {
return user_id();
- } else if (streql(cmd, "ls")) {
+ } else if (streql(cmd, "ls") || streql(cmd, "dir")) {
return ls(NEXT_ARGS);
} else if (streql(cmd, "tail")) {
return tail(NEXT_ARGS);
@@ -56,6 +56,16 @@ int main (ARGUMENTS) {
return head(NEXT_ARGS);
} else if (streql(cmd, "ed")) {
return ed(NEXT_ARGS);
+ } else if (streql(cmd, "tee")) {
+ return tee(NEXT_ARGS);
+ } else if (streql(cmd, "true")) {
+ return EXIT_SUCCESS;
+ } else if (streql(cmd, "false")) {
+ return EXIT_FAILURE;
+ } else if (streql(cmd, "whoami")) {
+ return whoami(NEXT_ARGS);
+ } else if (streql(cmd, "wc")) {
+ return wc(NEXT_ARGS);
} else {
error("error: invalid command %s", cmd);
}