summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTyler Murphy <tylerm@tylerm.dev>2023-05-02 00:37:30 -0400
committerTyler Murphy <tylerm@tylerm.dev>2023-05-02 00:37:30 -0400
commitab7109065ced6feac485e3a5621c0f9c52f7aeec (patch)
treea242b446b39ab8d4dcd248ec2c5a75f2c45522c0
parentupdate makefile (diff)
downloadlazysphere-ab7109065ced6feac485e3a5621c0f9c52f7aeec.tar.gz
lazysphere-ab7109065ced6feac485e3a5621c0f9c52f7aeec.tar.bz2
lazysphere-ab7109065ced6feac485e3a5621c0f9c52f7aeec.zip
tac, ls fixes
-rw-r--r--readme.md2
-rw-r--r--src/command.h2
-rw-r--r--src/commands/ls.c31
-rw-r--r--src/commands/tac.c105
-rw-r--r--src/main.c4
-rw-r--r--src/util/shared.c9
-rw-r--r--src/util/stack.c32
-rw-r--r--src/util/stack.h26
8 files changed, 196 insertions, 15 deletions
diff --git a/readme.md b/readme.md
index 9cb9dc4..a594b66 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`, `tee`, `true`, `false`, `tee`, `whoami`, `wc`, `xargs`
+`dd`, `cat`, `yes`, `echo`, `printf`, `id`, `groups`, `ls`, `tail`, `head`, `ed`, `tee`, `true`, `false`, `tee`, `whoami`, `wc`, `xargs`, `tac`
## How to
diff --git a/src/command.h b/src/command.h
index e596847..a73e3c8 100644
--- a/src/command.h
+++ b/src/command.h
@@ -1,4 +1,5 @@
#include "util/shared.h"
+#include "util/stack.h"
#include <stdint.h>
#include <stdlib.h>
@@ -31,3 +32,4 @@ COMMAND(tee);
COMMAND(whoami);
COMMAND(wc);
COMMAND(xargs);
+COMMAND(tac);
diff --git a/src/commands/ls.c b/src/commands/ls.c
index ce7206c..3aad1a1 100644
--- a/src/commands/ls.c
+++ b/src/commands/ls.c
@@ -9,11 +9,12 @@
#define FILE_COLOR ANSCII BLACK COLOR
#define DIR_COLOR ANSCII BOLD NEXT NORMAL BLUE COLOR
#define DIR_COLOR_EXEC ANSCII BACKGROUND GREEN NEXT NORMAL BLACK COLOR
-#define LINK_COLOR ANSCII BOLD NEXT HIGHLIGHT TURQUOISE COLOR
+#define 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;
@@ -32,6 +33,7 @@ struct FileInfo {
char mode[11];
char size[5];
int links;
+ int bytes;
bool set_uid;
bool set_gid;
bool exec;
@@ -45,6 +47,7 @@ struct FileListInfo {
int max_size;
int max_name;
int total_len;
+ int total_size;
};
static DIR* get_directory(char* path) {
@@ -173,6 +176,9 @@ static bool get_file_info(const char* file_path, const char* dir_path, struct Fi
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 * s.st_blksize;
+
return true;
}
@@ -186,10 +192,11 @@ static char* get_file_color(struct FileInfo* info) {
}
} 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 ||
- info->type == DT_SOCK
+ info->type == DT_BLK
) {
color = BLK_COLOR;
} else {
@@ -207,6 +214,13 @@ static char* get_file_color(struct FileInfo* info) {
}
static void list_files(struct FileInfo* files, int file_len, struct FileListInfo info, const char* dir_path) {
+
+ if (flags.more_info) {
+ char total[13];
+ print_file_size(info.total_size, total);
+ printf("total %s\n", total);
+ }
+
struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);
@@ -316,6 +330,7 @@ static void push_file(
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)++;
@@ -328,7 +343,6 @@ static bool recurse_directory(char* path) {
d = get_directory(path);
if (d == NULL) return false;
-
int capacity = 8;
int size = 0;
@@ -337,9 +351,9 @@ static bool recurse_directory(char* path) {
memset(&info, 0, sizeof(struct FileListInfo));
while((file = readdir(d)) != NULL) {
- if (file->d_type == DT_DIR) continue;
+ if (file->d_type == DT_DIR && !is_dot_dir(file->d_name)) continue;
if (!flags.hidden && prefix(".", file->d_name)) continue;
- if (is_dot_dir(file->d_name)) continue;
+ if (flags.hide_dot && is_dot_dir(file->d_name)) continue;
if (first) {
if (flags.colored == NO)
printf("\n%s:\n", path);
@@ -417,7 +431,7 @@ static void list_file_args(int start, int argc, char** argv) {
for (int i = start; i < argc; i++) {
if (is_dir(argv[i])) continue;
- push_file((struct FileInfo**) &files, &info, &size, &capacity, argv[i], ".");
+ push_file((struct FileInfo**) &files, &info, &size, &capacity, argv[i], argv[i][0] == '/' ? "" : ".");
}
if (size > 0) list_files(files, size, info, ".");
@@ -506,8 +520,7 @@ COMMAND(ls) {
else
printf("\n%s:\n", argv[i]);
}
- if (list_directory(argv[i]) && i + 1 != argc)
- if (titled && !flags.recurse) printf("\n");
+ list_directory(argv[i]);
}
return EXIT_SUCCESS;
diff --git a/src/commands/tac.c b/src/commands/tac.c
new file mode 100644
index 0000000..fbd0f74
--- /dev/null
+++ b/src/commands/tac.c
@@ -0,0 +1,105 @@
+#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 = end - start;
+ fseek(file, start, SEEK_SET);
+ for (int i = 0; i < len; i++) {
+ putchar(getc(file));
+ }
+ fflush(stdout);
+}
+
+static char stdin_path[PATH_MAX];
+
+static FILE* read_stdin() {
+ static bool read;
+ static FILE* file;
+
+ if (read) goto finished;
+ read = true;
+
+ srand(time(NULL));
+ int r = rand() % 1000000;
+ sprintf(stdin_path, "/tmp/%d.tac", r);
+ file = get_file(stdin_path, "w");
+
+ char c;
+ 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];
+ int read;
+ int total = 1;
+
+ stack_push_int(stack, 0);
+ rewind(file);
+ while ((read = fread(buf, 1, 1024, file)) > 0) {
+ for (int i = 0; i < read; i++) {
+ char c = buf[i];
+ if (c != '\n') continue;
+ stack_push_int(stack, total + i);
+ }
+ total += read;
+ }
+}
+
+static void tac_file(FILE* file) {
+ struct Stack stack;
+ stack_init(&stack, 80);
+
+ parse_file(file, &stack);
+
+ rewind(file);
+ int last, current;
+ 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) {
+
+ parse_help(argc, argv, help);
+
+ FILE* in = read_stdin();
+
+ if (argc < 1) {
+ tac_file(in);
+ return EXIT_SUCCESS;
+ }
+
+ for (int 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/main.c b/src/main.c
index 35899e2..7bd931e 100644
--- a/src/main.c
+++ b/src/main.c
@@ -21,7 +21,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, tee, true, false, tee, whoami, wc, xargs\n");
+ printf("\tdd, cat, yes, echo, printf, id, groups, ls, tail, head, ed, tee, true, false, tee, whoami, wc, xargs, tac\n");
return EXIT_SUCCESS;
}
argc--;
@@ -70,6 +70,8 @@ int main (ARGUMENTS) {
return wc(NEXT_ARGS);
} else if (streql(cmd, "xargs")) {
return xargs(NEXT_ARGS);
+ } else if (streql(cmd, "tac")) {
+ return tac(NEXT_ARGS);
} else {
error("error: invalid command %s", cmd);
}
diff --git a/src/util/shared.c b/src/util/shared.c
index e207c6d..3e6fca3 100644
--- a/src/util/shared.c
+++ b/src/util/shared.c
@@ -20,6 +20,11 @@ void error(const char* format, ...) {
FILE* get_file_s(const char* path, const char* type) {
struct stat s;
+ if (streql("-", path) && type[0] == 'r') {
+ clearerr(stdin);
+ fflush(stdin);
+ return stdin;
+ }
if (lstat(path, &s) < 0) {
if (type[0] != 'r') goto read;
fprintf(stderr, "error: failed to read %s: %s\n", path, strerror(errno));
@@ -40,10 +45,6 @@ read:
}
FILE* get_file(const char* path, const char* type) {
- if (streql("-", path) && type[0] == 'r') {
- clearerr(stdin);
- return stdin;
- }
FILE* file = get_file_s(path, type);
if (file == NULL) exit(EXIT_FAILURE);
return file;
diff --git a/src/util/stack.c b/src/util/stack.c
new file mode 100644
index 0000000..15d5a8e
--- /dev/null
+++ b/src/util/stack.c
@@ -0,0 +1,32 @@
+#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);
+}
diff --git a/src/util/stack.h b/src/util/stack.h
new file mode 100644
index 0000000..01a48e5
--- /dev/null
+++ b/src/util/stack.h
@@ -0,0 +1,26 @@
+#pragma once
+
+#include <stddef.h>
+#include <stdbool.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);
+
+inline void stack_push_int(struct Stack* stack, int value) {
+ stack_push(stack, &value, sizeof(int));
+}
+
+inline 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;
+}