lazysphere/src/commands/tac.c

106 lines
2 KiB
C
Raw Normal View History

2023-05-02 04:37:30 +00:00
#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;
}