diff options
author | Tyler Murphy <tylerm@tylerm.dev> | 2023-04-28 20:32:18 -0400 |
---|---|---|
committer | Tyler Murphy <tylerm@tylerm.dev> | 2023-04-28 20:32:18 -0400 |
commit | a94b5bcd943ff91c90d04000d6896fdaf5070392 (patch) | |
tree | 531451b0682e1b63a9b45870258e16e55900d8d1 /src/commands/tail.c | |
parent | ls tty fix (diff) | |
download | lazysphere-a94b5bcd943ff91c90d04000d6896fdaf5070392.tar.gz lazysphere-a94b5bcd943ff91c90d04000d6896fdaf5070392.tar.bz2 lazysphere-a94b5bcd943ff91c90d04000d6896fdaf5070392.zip |
added tail and head
Diffstat (limited to '')
-rw-r--r-- | src/commands/tail.c | 206 |
1 files changed, 175 insertions, 31 deletions
diff --git a/src/commands/tail.c b/src/commands/tail.c index 04f7f42..24d7b1f 100644 --- a/src/commands/tail.c +++ b/src/commands/tail.c @@ -2,19 +2,31 @@ #include <stdio.h> #include <string.h> +#include <sys/select.h> #include <sys/stat.h> +#include <unistd.h> -static void tail_file(FILE* file) { - char* ring[10]; - memset(ring, 0, sizeof(char*) * 10); +struct Flags { + bool lines; + int count; + bool print_headers; + bool dont_print_headers; + bool print_as_grow; + int grow_wait; +}; - int ring_len[10]; +static size_t tail_file_lines(FILE* file, unsigned int count, size_t skip) { + char* ring[count]; + memset(ring, 0, sizeof(char*) * count); + + int ring_len[count]; int index = 0; - int size = 0; + unsigned int size = 0; int read; - size_t len = 0; + fseek(file, skip, SEEK_SET); + size_t len = skip; char* line = NULL; while ((read = getline(&line, &len, file)) != -1) { @@ -23,57 +35,189 @@ static void tail_file(FILE* file) { ring_len[index] = read; index++; - index %= 10; - if (size < 10) size++; + index %= count; + if (size < count) size++; line = NULL; } - index += 10 - size; - index %= 10; + index += count - size; + index %= count; - for (int i = 0; i < size; i++) { + for (unsigned int i = 0; i < size; i++) { fwrite(ring[index], ring_len[index], 1, stdout); free(ring[index]); index += 1; - index %= 10; + index %= count; } free(line); fclose(file); + + return len; +} + +static size_t tail_file_chars(FILE* file, unsigned int count, size_t skip) { + char ring[count]; + memset(ring, 0, count); + + int index = 0; + unsigned int size = 0; + + fseek(file, skip, SEEK_SET); + int read = skip; + int c; + while((c = getc(file)) != EOF) { + ring[index] = c; + index++; + read++; + index %= count; + if (size < count) size++; + } + + index += count - size; + index %= count; + + for (unsigned int i = 0; i < size; i++) { + putchar(ring[index]); + index += 1; + index %= count; + } + + fclose(file); + + return read; } static void help() { - printf("Usage: tail [FILE]...\n\n"); + 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"); + 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 char* next_arg(int argc, char** argv, int index) { + if (index >= argc) { + error("error: expected another argument after option"); + } + return argv[index]; +} + +static void print_header(char* path, struct Flags* flags, 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, struct Flags* flags, bool many) { + FILE* file = get_file(path, "r"); + print_header(path, flags, many); + + size_t 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"); + }; +} + COMMAND(tail) { - if (argc < 1) { - tail_file(stdin); - return EXIT_SUCCESS; + + struct Flags flags; + flags.count = 10; + flags.dont_print_headers = false; + flags.print_headers = false; + flags.lines = true; + flags.print_as_grow = false; + flags.grow_wait = 10; + + int start = 0; + for (int i = 0; i < argc; i++) { + if (!prefix("-", argv[i])) break; + if (streql(argv[0], "--help")) help(); + start++; + int i_s = i; + for (size_t j = 1; j < strlen(argv[i_s]); j++) { + char c = argv[i_s][j]; + switch(c) { + case 'c': { + start++; + flags.lines = false; + char* arg = next_arg(argc, argv, ++i); + long int bkm = get_blkm(arg); + if (bkm < 1) { + error("error: bkm cannot be less than 1"); + } + flags.count = bkm; + break; + } + case 'n': { + start++; + flags.lines = true; + char* arg = next_arg(argc, argv, ++i); + long int bkm = get_blkm(arg); + if (bkm < 1) { + error("error: bkm cannot be less than 1"); + } + flags.count = bkm; + break; + } + 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': { + start++; + char* arg = next_arg(argc, argv, ++i); + long int sec = get_number(arg); + if (sec < 1) { + error("error: wait seconds cannot be less than 1"); + } + flags.grow_wait = sec; + break; + } + default: { + error("error: unknown option -%c", c); + } + } + } } - if (streql(argv[0], "--help")) help(); + int count = argc - start; - if (argc == 1) { - FILE* file = get_file(argv[0], "r"); - tail_file(file); + if (count < 1) { + tail_file_lines(stdin, 10, 0); 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); + if (count == 1) { + tail_file(argv[start], &flags, false); + return EXIT_SUCCESS; + } + + for (int i = 0; i < count; i++) { + tail_file(argv[start + i], &flags, true); } return EXIT_SUCCESS; |