/* 08May24: Eine Variation von der tail.c, was beliebig-lange Zeilen
 * unterstützen sollte.  Mehr Kommentare in der Datei. */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define N 10

int main()
{
     char *lines[N] = {};
     unsigned i = 0;

     for (;;) {
	  /* Hier legen wir den Speicher nicht auf dem Stack an,
	   * sondern lesen direkt auf Halden-Speicher.  Der Vorteil
	   * davon, ist das wir den gültigen Speicher dynamisch
	   * erweitern können. */

	  unsigned len = 1024;
	  /* Zum Nachdenken: Wie kann man diesen malloc(3) Aufruf hier
	   * vergessen. */
	  char *line = malloc(len);
	  if (NULL == line) {
	       perror("malloc");
	       exit(EXIT_FAILURE);
	  }

	  for (unsigned j = 0;; j++) {
	       /* Sobald wir erkennen, dass wir nicht genug Speicher
		* haben für die Zeile: */
	       if (j >= len) {
		    /* Hier vergrößern wir den Speicher linear, aber
		     * man kann auch schauen wie das Verhalten sich
		     * verändert wenn man einen anderen Ansatz nimmt. */
		    len += 1024;
		    line = realloc(line, len);
		    if (NULL == line) {
			 perror("realloc");
			 exit(EXIT_FAILURE);
		    }
	       }

	       /* Anstatt mit fgets(3) zu lesen, machen wir hier ein
		* Beispiel wie man Zeichenweise einlesen kann.  Achtet
		* auf den Rückgabe-Typ von fgetc(3)! */
	       int c = fgetc(stdin);
	       if (c == EOF) {
		    if (ferror(stdin)) {
			 perror("fgetc");
			 exit(EXIT_FAILURE);
		    } else {
			 /* Goto ist hier IMO akzeptabel, weil man
			  * nach vorne springt und nur ein "break"
			  * nachbaut. */
			 goto end_of_file;
		    }
	       }

	       line[j] = c;
	       if (line[j] == '\n') {
		    /* Hier brechen wir die "Zeile-Einlesen" Schleife. */
		    break;
	       }
	  }

	  free(lines[i % N]);
	  lines[i % N] = line;
	  if (lines[i % N] == NULL) {
	       perror("strdup");
	       exit(EXIT_FAILURE);
	  }
	  i++;
     }

end_of_file:
     for (unsigned j = 0; j < N; j++) {
	  if (lines[(i + j) % N] == NULL) break;
	  
	  fputs(lines[(i + j) % N], stdout);
	  free(lines[(i + j) % N]);
     }

     if (EOF == fflush(stdout)) {
	  perror("fflush");
	  exit(EXIT_FAILURE);
     }

     return EXIT_FAILURE;
}