105 lines
2 KiB
C
105 lines
2 KiB
C
#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, ¤t)) {
|
|
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;
|
|
}
|