/* 03May24: Eine kleine Implementierung von head(1) mit * Unterstuetzung fuer beliebig andere Zeilen. * * Denkt daran die Aufgabe mit Valgrind zu testen, bspw: * * $ valgrind ./head < /dev/urandom */ #include #include #include #include /* Idee: wir speichern die Zeile in einem char*, welches wir dynamisch * erweitern wenn der Puffer nicht gross genug war. */ #define LINE_BLOCK (1 << 10) /* Hier eine kleine Hillfsfunktion, um zu Pruefen ob eine Zeile * bereits ein Newline hat oder nicht. */ static bool has_newline(char *s) { /* oder return strchr(line, '\n') == NULL; aber wir nehmen an, * dass es immer nur ein Newline am Ende der Zeile gibt: */ return strlen(s) > 0 && s[strlen(s)-1] == '\n'; } int main() { /* Vereinfachung: Wir lesen bis zu 10 Zeilen an, man koennte mit * strtol(3) aus argv einen Parameter auslesen. */ for (int i = 0; i < 10; i++) { /* Der Fehler am 03May24 war, dass wir den gleichen Speicher * fuer jede Zeile benutzen. Stattdessen muss man jede * Zeile neu anlegen UND spaeter aufraeumen */ size_t cap = 0; char *line = NULL; /* Diese Schleife laeuft so oft durch, wie man braucht um * mit LINE_BLOCK grossen Bloecken den Datenstrom auszulesen * um eine Zeile abzuarbeiten */ for (int j = 0;; j++) { cap += LINE_BLOCK; /* Hier benutzt der erste Durchlauf den Trick * realloc(NULL, n) = malloc(n). */ line = realloc(line, cap); if (line == NULL) { perror("realloc"); exit(EXIT_FAILURE); } /* Erstmal schauen ob fgets(3) ueberhaupt funktioniert: */ if (fgets(line + j * LINE_BLOCK, LINE_BLOCK, stdin)) { /* Mit fgets(3) muessen wir nur pruefen ob die * Zeile ein LF hat, ansonten brauchen wir mehr * Speicher. */ if (has_newline(line)) { printf("%s", line); break; } else { continue; } } else { /* Bei einem "Fehler" unterschieden wir zwischen * dem Ende der Eingabe (bspw. wegen Ctrl-D) oder * einem echtem Fehler. */ if (feof(stdin)) { return EXIT_SUCCESS; } else { perror("fgets"); exit(EXIT_FAILURE); } } } /* Bonusaufgabe: Eigentlich kann man den Speicher * wiederbenutzen, und nicht immer von Null anfangen. */ cap = LINE_BLOCK; free(line); } }