One of my first programming obsessions was online communications. I wrote several modem programs for the TRS-80 (in Z80 Assembly) and then moved to the IBM PC/MS-DOS where I coded communications programs in both Assembly and C. I learned a few things.
One of the surprising things I learned was how to erase text on the screen. This process involves moving the cursor, which works differently online than it does on the terminal screen.
When programming a single-user, single-tasking system like MS-DOS, a programmer has direct control over the computer’s hardware. Back then, I knew nothing of stream input and output as it’s used in C programming. But when I wrote online programs, I had to tussle with stream I/O which works differently from manipulating the screen directly.
For example, on the computer I could send a newline (\n
) to the screen and the cursor sped back to the start of the line and dropped down a line. If the cursor is at the bottom row of the screen, the lines above scroll upwards and a new blank line is inserted. All this action must be manually coded when working online: A newline output involves both a carriage return and a linefeed.
Backing up and erasing is another issue. To backup the cursor, you send control code 8 (^H). This code moves the cursor back a notch, but it doesn’t erase. Backup is non-destructive. Yet most programs implement a destructive backup.
The following code outputs a line of 20 Xs. The program pauses. Then code outputs 20 backspace characters.
2024_07_06-Lesson-a.c
#include <stdio.h> #include <unistd.h> int main() { int x; for(x=0;x<20;x++) putchar('X'); fflush(stdout); sleep(1); for(x=0;x<20;x++) putchar('\b'); putchar('\n'); return 0; }
The code outputs 20 Xs. The output buffer is flushed, fflush(stdout)
, to make the line appear. Otherwise, text isn’t output until a newline is sent.
The unistd.h
header file is required for the sleep() function. This function is defined by the POSIX standard; it’s not part of the standard C library. It pauses one second for you to behold the line of Xs. Then 20 backspace characters are output. If you’re quick, you can see the cursor scurry back to the start of the line — but nothing is erased!
Sample output:
XXXXXXXXXXXXXXXXXXXX
The reason the line isn’t erased is because backspace is non-destructive. The ^H character merely moves the cursor back one character position. To make it destructive, as I learned when programming online communications, you must output three characters: backspace, space, backspace.
In the days of 300 baud modems, you could see the cursor “wiggle” as it backed up and erased text on the screen. Today the action happens too quickly, as you can see by this update to the code:
2024_07_06-Lesson-b.c
#include <stdio.h> #include <unistd.h> int main() { int x; for(x=0;x<20;x++) putchar('X'); fflush(stdout); sleep(1); for(x=0;x<20;x++) printf("\b \b"); putchar('\n'); return 0; }
The printf() statement outputs a string backspace, space, backspace. The action takes place quickly in the terminal window, which is set to 38,400 baud on my system — 128 times faster than that old 300 baud modem. Regardless of speed, the effect is to backup and erase the line of input.
For the output, the row of Xs appears, the program pauses, then the line is erased. This weird method worked online years ago, and it still works today.
For next week’s Lesson, I cover another way to accomplish the same thing.