lazysphere/command/tail.c

244 lines
5.1 KiB
C
Raw Permalink Normal View History

2023-05-06 04:39:44 +00:00
#include "command.h"
#include "lslib.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
2023-04-28 19:13:10 +00:00
2023-05-01 22:43:32 +00:00
static struct {
2023-04-29 00:32:18 +00:00
bool lines;
int count;
bool print_headers;
bool dont_print_headers;
bool print_as_grow;
int grow_wait;
2023-05-01 22:43:32 +00:00
} flags;
2023-04-28 19:13:10 +00:00
2023-04-29 00:32:18 +00:00
static size_t tail_file_lines(FILE* file, unsigned int count, size_t skip) {
2023-05-04 20:10:37 +00:00
char** ring;
int* ring_len;
int index, read;
unsigned int size, i;
size_t len;
char* line;
2023-05-15 01:43:02 +00:00
ring = xalloc(sizeof(char*) * count);
2023-04-29 00:32:18 +00:00
memset(ring, 0, sizeof(char*) * count);
2023-05-15 01:43:02 +00:00
ring_len = xalloc(sizeof(int) * count);
2023-04-28 19:13:10 +00:00
2023-05-04 20:10:37 +00:00
index = 0;
size = 0;
2023-04-28 19:13:10 +00:00
2023-04-29 00:32:18 +00:00
fseek(file, skip, SEEK_SET);
2023-05-04 20:10:37 +00:00
len = skip;
line = NULL;
2023-04-28 19:13:10 +00:00
while ((read = getline(&line, &len, file)) != -1) {
if (ring[index] != NULL) free(ring[index]);
ring[index] = line;
ring_len[index] = read;
index++;
2023-04-29 00:32:18 +00:00
index %= count;
if (size < count) size++;
2023-04-28 19:13:10 +00:00
line = NULL;
}
2023-04-29 00:32:18 +00:00
index += count - size;
index %= count;
2023-05-04 20:10:37 +00:00
for (i = 0; i < size; i++) {
2023-04-28 19:13:10 +00:00
fwrite(ring[index], ring_len[index], 1, stdout);
free(ring[index]);
index += 1;
2023-04-29 00:32:18 +00:00
index %= count;
2023-04-28 19:13:10 +00:00
}
free(line);
fclose(file);
2023-05-04 20:10:37 +00:00
free(ring);
free(ring_len);
2023-04-29 00:32:18 +00:00
return len;
}
static size_t tail_file_chars(FILE* file, unsigned int count, size_t skip) {
2023-05-04 20:10:37 +00:00
char* ring;
int index;
unsigned int size, i;
int read, c;
2023-05-15 01:43:02 +00:00
ring = xalloc(sizeof(char) * count);
2023-04-29 00:32:18 +00:00
memset(ring, 0, count);
2023-05-04 20:10:37 +00:00
index = 0;
size = 0;
2023-04-29 00:32:18 +00:00
fseek(file, skip, SEEK_SET);
2023-05-04 20:10:37 +00:00
read = skip;
2023-04-29 00:32:18 +00:00
while((c = getc(file)) != EOF) {
ring[index] = c;
index++;
read++;
index %= count;
if (size < count) size++;
}
index += count - size;
index %= count;
2023-05-04 20:10:37 +00:00
for (i = 0; i < size; i++) {
2023-04-29 00:32:18 +00:00
putchar(ring[index]);
index += 1;
index %= count;
}
fclose(file);
return read;
2023-04-28 19:13:10 +00:00
}
2023-05-01 22:43:32 +00:00
static void help(void) {
2023-04-29 00:32:18 +00:00
printf("Usage: tail [OPTIONS] [FILE]...\n\n");
2023-04-28 19:13:10 +00:00
printf("Print last 10 lines of FILEs (or stdin) to.\n");
2023-04-29 00:32:18 +00:00
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");
2023-04-28 19:13:10 +00:00
exit(EXIT_SUCCESS);
}
2023-05-01 22:43:32 +00:00
static void print_header(char* path, bool many) {
if (flags.dont_print_headers) return;
if (!many && !flags.print_headers) return;
2023-04-29 00:32:18 +00:00
if (streql("-", path)) {
printf("\n==> standard input <==\n");
} else {
printf("\n=>> %s <==\n", path);
}
}
2023-05-01 22:43:32 +00:00
static void tail_file(char* path, bool many) {
2023-05-04 20:10:37 +00:00
FILE* file;
size_t skip;
file = get_file(path, "r");
2023-05-01 22:43:32 +00:00
print_header(path, many);
2023-04-29 00:32:18 +00:00
2023-05-04 20:10:37 +00:00
skip = 0;
2023-04-29 00:32:18 +00:00
while (true) {
2023-05-01 22:43:32 +00:00
if (flags.lines) {
skip = tail_file_lines(file, flags.count, skip);
2023-04-29 00:32:18 +00:00
} else {
2023-05-01 22:43:32 +00:00
skip = tail_file_chars(file, flags.count, skip);
2023-04-29 00:32:18 +00:00
}
2023-05-01 22:43:32 +00:00
if (!flags.print_as_grow) break;
sleep(flags.grow_wait);
2023-04-29 00:32:18 +00:00
get_file(path, "r");
};
}
2023-05-01 22:43:32 +00:00
static int short_arg(char c, char* next) {
switch (c) {
case 'c': {
2023-05-04 20:10:37 +00:00
long int bkm;
2023-05-01 22:43:32 +00:00
flags.lines = false;
2023-05-04 20:10:37 +00:00
2023-05-01 22:43:32 +00:00
check_arg(next);
2023-05-04 20:10:37 +00:00
bkm = get_blkm(next);
2023-05-01 22:43:32 +00:00
if (bkm < 1) {
2023-05-03 16:17:56 +00:00
error("bkm cannot be less than 1");
2023-05-01 22:43:32 +00:00
}
2023-05-04 20:10:37 +00:00
2023-05-01 22:43:32 +00:00
flags.count = bkm;
return ARG_USED;
}
case 'n': {
2023-05-04 20:10:37 +00:00
long int bkm;
2023-05-01 22:43:32 +00:00
flags.lines = true;
2023-05-04 20:10:37 +00:00
2023-05-01 22:43:32 +00:00
check_arg(next);
2023-05-04 20:10:37 +00:00
bkm = get_blkm(next);
2023-05-01 22:43:32 +00:00
if (bkm < 1) {
2023-05-03 16:17:56 +00:00
error("bkm cannot be less than 1");
2023-05-01 22:43:32 +00:00
}
2023-05-04 20:10:37 +00:00
2023-05-01 22:43:32 +00:00
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': {
2023-05-04 20:10:37 +00:00
long int sec;
2023-05-01 22:43:32 +00:00
check_arg(next);
2023-05-04 20:10:37 +00:00
sec = get_number(next);
2023-05-01 22:43:32 +00:00
if (sec < 1) {
2023-05-03 16:17:56 +00:00
error("wait seconds cannot be less than 1");
2023-05-01 22:43:32 +00:00
}
2023-05-04 20:10:37 +00:00
2023-05-01 22:43:32 +00:00
flags.grow_wait = sec;
return ARG_USED;
}
2023-05-03 16:17:56 +00:00
default:
return ARG_INVALID;
2023-05-01 22:43:32 +00:00
}
return ARG_UNUSED;
}
2023-05-15 14:57:33 +00:00
COMMAND(tail_main) {
2023-04-29 00:32:18 +00:00
2023-05-04 20:10:37 +00:00
int start, count, i;
2023-04-29 00:32:18 +00:00
flags.count = 10;
flags.dont_print_headers = false;
flags.print_headers = false;
flags.lines = true;
flags.print_as_grow = false;
flags.grow_wait = 10;
2023-05-04 20:10:37 +00:00
start = parse_args(argc, argv, help, short_arg, NULL);
2023-04-28 19:13:10 +00:00
2023-05-04 20:10:37 +00:00
count = argc - start;
2023-04-28 19:13:10 +00:00
2023-04-29 00:32:18 +00:00
if (count < 1) {
tail_file_lines(stdin, 10, 0);
2023-04-28 19:13:10 +00:00
return EXIT_SUCCESS;
}
2023-04-29 00:32:18 +00:00
if (count == 1) {
2023-05-01 22:43:32 +00:00
tail_file(argv[start], false);
2023-04-29 00:32:18 +00:00
return EXIT_SUCCESS;
}
2023-05-04 20:10:37 +00:00
for (i = 0; i < count; i++) {
2023-05-01 22:43:32 +00:00
tail_file(argv[start + i], true);
2023-04-28 19:13:10 +00:00
}
return EXIT_SUCCESS;
}