Programming lesson
Eigenes Autoscroll-Programm in C: Terminalsteuerung mit Signalen und ANSI-Escape-Sequenzen
Lerne, wie du mit C und Linux-Signalen ein automatisch scrollendes Datei-Viewer-Programm schreibst – inklusive Tipps zu Signalhandling, Terminalsteuerung und ANSI-Codes. Ideal für Studierende der Systemprogrammierung.
Autoscroll – Selbstscrollender Dateibetrachter in C: Ein praxisnahes Tutorial
In diesem Tutorial erfährst du Schritt für Schritt, wie ein autoscroll-Programm funktioniert, das eine Textdatei zeilenweise im Terminal anzeigt und automatisch nach oben scrollt. Das Projekt kombiniert Signalverarbeitung, Terminalsteuerung mit ANSI-Escape-Sequenzen und Datei-I/O – typische Themen im Csci493.66 Assignment 5. Ob du dich auf eine Prüfung vorbereitest oder einfach deine C-Kenntnisse vertiefen willst: Dieses Tutorial gibt dir das nötige Rüstzeug.
Was ist Autoscroll und warum ist es relevant?
Stell dir vor, du liest einen langen Logfile auf einem Server, der ständig neue Zeilen produziert. Ein manuelles Scrollen wäre mühsam. Ein automatisch scrollender Dateibetrachter löst das Problem: Er zeigt die ersten Zeilen, wartet eine Sekunde, scrollt eine Zeile nach oben und aktualisiert die Anzeige. Genau das macht autoscroll. Es nutzt Signale wie SIGALRM, um den Takt zu steuern, und ANSI-Escape-Sequenzen, um den Cursor zu positionieren und den Bildschirm zu löschen.
Das Thema ist hochaktuell: In Zeiten von KI-Chatbots, die Logdaten in Echtzeit streamen, oder Live-Ticker-Apps, die Nachrichten automatisch aktualisieren, ist das Verständnis solcher Mechanismen wertvoll. Sogar in der Spieleentwicklung werden ähnliche Techniken verwendet, um Statusleisten oder HUDs zu aktualisieren.
Grundlagen: Signale und ihre Handler
Ein Signal ist eine asynchrone Benachrichtigung an einen Prozess. alarm() sendet nach einer bestimmten Zeit das Signal SIGALRM. Da alarm() kein Timer ist, muss der Signalhandler jedes Mal alarm() erneut aufrufen, um periodische Alarme zu erhalten.
Beispiel für einen einfachen Handler:
void handle_alarm(int sig) {
// Bildschirm aktualisieren, scrollen
alarm(1); // Nächstes Signal in 1 Sekunde
}Wichtig: Der Handler muss auf globale Variablen zugreifen können, da main() die Daten initialisiert und der Handler keine Parameter außer der Signalnummer erhält. Daher werden die Datei-Inhalte, Zeilenanzahl und Cursorposition als global deklariert.
Terminalsteuerung mit ANSI-Escape-Sequenzen
ANSI-Escape-Sequenzen sind spezielle Zeichenfolgen, die mit \033[ beginnen. Sie steuern Cursorposition, Bildschirminhalt und Textformatierung. Für autoscroll benötigst du:
- Cursor positionieren:
\033[row;colH - Bildschirm löschen:
\033[2J - Scrollbuffer löschen:
\033[3J - Cursor verstecken:
\033[?25l
Ein Beispiel: printf("\033[2J\033[1;1H"); löscht den Bildschirm und setzt den Cursor auf (1,1).
Datei einlesen und Zeilen verwalten
Das Programm liest die gesamte Datei in den Speicher. Danach sucht es nach Newline-Zeichen, um die Zeilenanfänge zu speichern. Das erleichtert das spätere Scrollen: Du musst nur den Index des ersten anzuzeigenden Zeilenanfangs erhöhen.
Beispiel für das Einlesen:
char *buf;
struct stat st;
int fd = open(filename, O_RDONLY);
fstat(fd, &st);
buf = malloc(st.st_size + 1);
read(fd, buf, st.st_size);
buf[st.st_size] = '\0';Anschließend bestimmst du die Zeilenumbrüche und speicherst die Offsets in einem Array. Beachte: Zeilen länger als die Terminalbreite werden umgebrochen dargestellt. Das Programm muss die effektive Zeilenhöhe berechnen: Eine Zeile von 160 Zeichen bei 80 Spalten belegt 2 Zeilen. Autoscroll sollte so lange warten, bis die gesamte Zeile sichtbar ist, bevor sie angezeigt wird.
Statusleiste und Uhrzeit
Die unterste Zeile (Zeile R) ist die Statusleiste. Links steht die aktuelle Uhrzeit im Format HH:MM:SS, rechts daneben ab Spalte 10 die Zeilenbereiche, z.B. „Lines: 100-122“. Die Uhrzeit wird jede Sekunde aktualisiert – auch wenn das Scrollen pausiert ist.
Um die Uhrzeit zu ermitteln, verwendest du time() und localtime():
time_t now = time(NULL);
struct tm *t = localtime(&now);
printf("\033[%d;1H%02d:%02d:%02d", R, t->tm_hour, t->tm_min, t->tm_sec);Pausieren und Fortsetzen mit CTRL-Z und CTRL-C
Der Benutzer kann mit CTRL-Z (SIGTSTP) das Scrollen pausieren. Die Uhr läuft weiter, aber die Datei scrollt nicht. Mit CTRL-C (SIGINT) wird das Scrollen fortgesetzt. Wichtig: Wenn das Scrollen läuft, hat CTRL-C keine Wirkung; wenn es pausiert ist, hat CTRL-Z keine Wirkung.
Die main()-Funktion wartet mit sigwait() auf diese Signale. Dazu blockierst du die relevanten Signale mit sigprocmask() und rufst dann sigwait() in einer Schleife auf. Beispiel:
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGINT);
sigaddset(&set, SIGTSTP);
sigprocmask(SIG_BLOCK, &set, NULL);
int sig;
while (1) {
sigwait(&set, &sig);
if (sig == SIGTSTP) { /* pause scrolling */ }
else if (sig == SIGINT) { /* resume scrolling */ }
}Beachte: Der Cursor muss immer an Position (R, C-2) parken – das ist die untere rechte Ecke der Statusleiste.
Fehlerbehandlung und Benutzungshinweise
Wenn der Benutzer keinen Dateinamen angibt, gib eine Usage-Message auf stderr aus. Auch bei ungültiger Option -s (z.B. negative Zahl oder >60) solltest du eine Fehlermeldung ausgeben. Beispiel:
fprintf(stderr, "Usage: autoscroll [-s secs] textfile\n");
exit(EXIT_FAILURE);Das Programm sollte alle Fehler auf stderr melden und mit einem Nicht-Null-Exitcode beenden.
Praktische Tipps zum Debuggen
Signalhandler und Bildschirmsteuerung machen das Debuggen tricky. Verwende gdb und valgrind. Öffne ein zweites Terminal, ermittle mit tty dessen Gerätedatei (z.B. /dev/pts/2) und schreibe dort Diagnoseausgaben hin:
FILE *debug = fopen("/dev/pts/2", "w");
fprintf(debug, "Aktuelle Zeile: %d\n", current_line);
fflush(debug);So siehst du, was dein Programm denkt, ohne die Terminalausgabe zu stören.
Zusammenfassung und Ausblick
Mit diesem Tutorial hast du die Grundlagen für ein autoscroll-Programm verstanden: Signalverarbeitung mit alarm(), ANSI-Escape-Sequenzen für die Terminalsteuerung, Datei-I/O und die Verwaltung von Zeilenumbrüchen. Diese Konzepte sind nicht nur für Systemprogrammierung essenziell, sondern auch für moderne Anwendungen wie Echtzeit-Dashboards, KI-Streaming oder interaktive Kommandozeilen-Tools.
Probiere es selbst aus: Implementiere die fehlenden Teile, teste mit verschiedenen Dateigrößen und passe die Scrollgeschwindigkeit an. Viel Erfolg bei deinem Csci493.66 Assignment 5!