Counting Terminal Rows and Columns

I enjoy programming a computer the old fashioned way, in the text mode terminal window. Yes, it’s now a sad little “app” floating on a graphical screen. This burden doesn’t remove the charm, but it does raise an interesting issue when you try to get text mode output just right: How many rows and columns are there in the terminal window?

In ancient times, the text mode window size was fixed and consistent. On an IBM PC, it was 80 columns in 25 rows. My TRS-80 Model III had a terminal screen of 64 columns by 16 rows. Later computers let you adjust the terminal size. Even today in Windows, Linux, or macOS, the terminal app’s dimensions are adjustable — sometimes just by re-sizing the window.

Various methods exist to fetch the terminal size, returning the number of character columns and rows so that your program can neatly output text. The best way to address screen size, as well as all text mode programming, is to use the NCurses library. Time for a shameless plug for my NCurses eBook. Other (less expensive to you and less profitable for me) methods exist as well.

At the prompt, use the tput command to divine the number of rows (lines) and columns:

$ tput lines && tput cols
24
80

If the terminal is running the bash shell, variables $LINES and $COLUMNS hold the details:

$ echo $LINES && echo $COLUMNS
24
80

These shell variables aren’t the same as environment variables, so you can’t read the environment to fetch their values.

Nope, you must use the ioctl() function to dig into the terminal’s guts and obtain the line (row) and column sizes for the current terminal. This method may be cryptic, but it’s consistent.

The ioctl() function is defined in the sys/ioctl.h header file. It reads details about special files — and remember that all devices in Unix/Linux/macOS are treated as files. The terminal is just another file, but you need the ioctl() (input/output control) function to obtain or set these details. Here is the man page format:

int ioctl(int fildes, unsigned long request, ...);

The first argument, fildes, represents an open file descriptor. The second argument, request, is the specific information required, expressed as a defined constant. The final argument(s) hold the results. The return value is zero upon success or an error value otherwise.

To read the current terminal’s data, the filedes is STDOUT_FILENO. This defined constant, declared in the unistd.h header, represents the current output device.

The second argument is TIOCGWINSZ, which I assume stands for Terminal Input/Output Current Golly Window Size, though I have my doubts about the word “Golly.” Regardless, use this argument to obtain information about the terminal window.

The final argument is the address of a winsize structure to hold the results. Structure members ws_row and ws_col contain the row and column (line) values. Here’s code:

2023_02_04-Lesson.c

#include <stdio.h>
#include <unistd.h>
#include <sys/ioctl.h>

int main()
{
    struct winsize w;

    ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);

    printf("This terminal window is %d rows by %d columns\n",
            w.ws_row,
            w.ws_col
          );

    return(0);
}

The ioctl() function at Line 9 reads the terminal information, stuffing the details into winsize variable w. The printf() statement outputs the current terminal size values:

This terminal window is 24 rows by 80 columns

The ioctl() function is powerful and, obviously, handy. Yet it seems scary. Any apprehension probably comes from the function’s scant documentation. I would love to probe the winsize structure further, but without a well written guide or further details, yes it’s scary.

2 thoughts on “Counting Terminal Rows and Columns

  1. “Yes, it’s now a sad little “app” floating on a graphical screen.”

    I think you can configure Linux distros to not use any desktop such as Cinnamon, Gnome etc. so that you just get a terminal when you switch on, like in the Neolithic era.

    With Windows up to 3.1 (which was a DOS program, not an OS) you could hack autoexec.bat to not run win in the last line, so you’d just get the DOS C:/>

  2. Ah, those were the days.

    My first Linux computer ran Red Hat Linux. It used only the text screen. You could have several terminal windows, but they were all full screen.

    When I ran the gookin.com server out of my office, it was on a FreeBSD box that only ran in text mode.

    I think you can configure Windows today to launch in text mode. The thought terrifies me.

Leave a Reply