#include "../command.h" #include #include #include 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; }