summaryrefslogtreecommitdiff
path: root/command/tac.c
diff options
context:
space:
mode:
Diffstat (limited to 'command/tac.c')
-rw-r--r--command/tac.c119
1 files changed, 119 insertions, 0 deletions
diff --git a/command/tac.c b/command/tac.c
new file mode 100644
index 0000000..9e9e48e
--- /dev/null
+++ b/command/tac.c
@@ -0,0 +1,119 @@
+#include "command.h"
+#include "lslib.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <limits.h>
+#include <time.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, i;
+
+ len = end - start;
+ fseek(file, start, SEEK_SET);
+
+ for (i = 0; i < len; i++) {
+ putchar(getc(file));
+ }
+
+ fflush(stdout);
+}
+
+static char stdin_path[PATH_MAX];
+
+static FILE* read_stdin (void) {
+ static bool read;
+ static FILE* file;
+ int r;
+ char c;
+
+ if (read) goto finished;
+ read = true;
+
+ srand(time(NULL));
+
+ r = rand() % 1000000;
+
+ sprintf(stdin_path, "/tmp/%d.tac", r);
+ file = get_file(stdin_path, "w");
+
+ 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], c;
+ int read, i;
+ int total = 1;
+
+ stack_push_int(stack, 0);
+ rewind(file);
+ while ((read = fread(buf, 1, 1024, file)) > 0) {
+ for (i = 0; i < read; i++) {
+ c = buf[i];
+ if (c != '\n') continue;
+ stack_push_int(stack, total + i);
+ }
+ total += read;
+ }
+}
+
+static void tac_file(FILE* file) {
+ struct Stack stack;
+ int last, current;
+
+ stack_init(&stack, 80);
+ parse_file(file, &stack);
+ rewind(file);
+
+ 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) {
+
+ FILE* in;
+ int i;
+
+ parse_help(argc, argv, help);
+
+ in = read_stdin();
+
+ if (argc < 1) {
+ tac_file(in);
+ return EXIT_SUCCESS;
+ }
+
+ for (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;
+}