summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTyler Murphy <tylerm@tylerm.dev>2023-04-28 15:13:10 -0400
committerTyler Murphy <tylerm@tylerm.dev>2023-04-28 15:13:10 -0400
commit7a1eef12299f4b030bfb77d9bbb133d0ba2ee674 (patch)
tree61d7008b25e37799318db4030b86f85fc0059275
parentfix missing newline on single row output (diff)
downloadlazysphere-7a1eef12299f4b030bfb77d9bbb133d0ba2ee674.tar.gz
lazysphere-7a1eef12299f4b030bfb77d9bbb133d0ba2ee674.tar.bz2
lazysphere-7a1eef12299f4b030bfb77d9bbb133d0ba2ee674.zip
add tail
Diffstat (limited to '')
-rw-r--r--readme.md2
-rw-r--r--src/command.h1
-rw-r--r--src/commands/cat.c11
-rw-r--r--src/commands/tail.c80
-rw-r--r--src/main.c4
-rw-r--r--src/shared.c20
-rw-r--r--src/shared.h1
7 files changed, 115 insertions, 4 deletions
diff --git a/readme.md b/readme.md
index 3dfe6e5..3440299 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`
+`dd`, `cat`, `yes`, `echo`, `printf`, `id`, `groups`, `ls`, `tail`
## How to
diff --git a/src/command.h b/src/command.h
index 4a2c50b..939886d 100644
--- a/src/command.h
+++ b/src/command.h
@@ -17,3 +17,4 @@ COMMAND(print);
COMMAND_EMPTY(groups);
COMMAND_EMPTY(user_id);
COMMAND(ls);
+COMMAND(tail);
diff --git a/src/commands/cat.c b/src/commands/cat.c
index f5622e8..8e22706 100644
--- a/src/commands/cat.c
+++ b/src/commands/cat.c
@@ -1,7 +1,9 @@
#include "../command.h"
#include <ctype.h>
+#include <errno.h>
#include <string.h>
+#include <sys/stat.h>
struct Flags {
bool number_lines;
@@ -138,6 +140,15 @@ COMMAND(cat) {
continue;
} else {
files = true;
+ struct stat s;
+ if (stat(argv[i], &s) < 0) {
+ printf("error: failed to read %s: %s\n", argv[i], strerror(errno));
+ continue;
+ }
+ if (!S_ISREG(s.st_mode)) {
+ printf("error: %s is not a file\n", argv[i]);
+ continue;
+ }
FILE* in = get_file(argv[i], "r");
cat_file(in, flags);
fclose(in);
diff --git a/src/commands/tail.c b/src/commands/tail.c
new file mode 100644
index 0000000..04f7f42
--- /dev/null
+++ b/src/commands/tail.c
@@ -0,0 +1,80 @@
+#include "../command.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+
+static void tail_file(FILE* file) {
+ char* ring[10];
+ memset(ring, 0, sizeof(char*) * 10);
+
+ int ring_len[10];
+
+ int index = 0;
+ int size = 0;
+
+ int read;
+ size_t len = 0;
+ char* 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 %= 10;
+ if (size < 10) size++;
+
+ line = NULL;
+ }
+
+ index += 10 - size;
+ index %= 10;
+
+ for (int i = 0; i < size; i++) {
+ fwrite(ring[index], ring_len[index], 1, stdout);
+ free(ring[index]);
+ index += 1;
+ index %= 10;
+ }
+
+ free(line);
+ fclose(file);
+}
+
+static void help() {
+ printf("Usage: tail [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");
+ exit(EXIT_SUCCESS);
+}
+
+COMMAND(tail) {
+ if (argc < 1) {
+ tail_file(stdin);
+ return EXIT_SUCCESS;
+ }
+
+ if (streql(argv[0], "--help")) help();
+
+ if (argc == 1) {
+ FILE* file = get_file(argv[0], "r");
+ tail_file(file);
+ return EXIT_SUCCESS;
+ }
+
+ for (int i = 0; i < argc; i++) {
+ FILE* file;
+ if (streql("-", argv[i])) {
+ file = stdin;
+ } else {
+ file = get_file_s(argv[i], "r");
+ if (file == NULL) continue;
+ }
+ printf("\n==> %s <==\n", argv[i]);
+ tail_file(file);
+ }
+
+ return EXIT_SUCCESS;
+}
diff --git a/src/main.c b/src/main.c
index 63aa775..ce89210 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\n");
+ printf("\tdd, cat, yes, echo, printf, id, groups, ls, tail\n");
return EXIT_SUCCESS;
}
argc--;
@@ -50,6 +50,8 @@ int main (ARGUMENTS) {
return user_id();
} else if (streql(cmd, "ls")) {
return ls(NEXT_ARGS);
+ } else if (streql(cmd, "tail")) {
+ return tail(NEXT_ARGS);
} else {
error("error: invalid command %s", cmd);
}
diff --git a/src/shared.c b/src/shared.c
index b167e6f..8d0dcca 100644
--- a/src/shared.c
+++ b/src/shared.c
@@ -5,6 +5,7 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
+#include <sys/stat.h>
void error(const char* format, ...) {
va_list list;
@@ -15,14 +16,29 @@ void error(const char* format, ...) {
exit(EXIT_FAILURE);
}
-FILE* get_file(const char* path, const char* type) {
+FILE* get_file_s(const char* path, const char* type) {
+ struct stat s;
+ if (stat(path, &s) < 0) {
+ fprintf(stderr, "error: failed to read %s: %s\n", path, strerror(errno));
+ return NULL;
+ }
+ if (!S_ISREG(s.st_mode)) {
+ fprintf(stderr, "error: %s is not a file\n", path);
+ return NULL;
+ }
FILE* file = fopen(path, type);
if (file == NULL) {
- error("error: failed to open file %s: %s", path, strerror(errno));
+ fprintf(stderr, "error: failed to open file %s: %s\n", 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);
diff --git a/src/shared.h b/src/shared.h
index 4556d5d..251a993 100644
--- a/src/shared.h
+++ b/src/shared.h
@@ -7,6 +7,7 @@
__attribute__ ((__format__(printf, 1, 2)))
void error(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);