Question

Is there any reliable way of getting the number of columns/rows of the current output terminal window?

I want to retrieve these numbers in a C/C++ program.

I'm looking for a GNU/Linux solution primarily, but also need a Windows solution.

Was it helpful?

Solution 2

For Unix(-based), use ioctl(2) and TIOCGWINSZ:


#include <sys/ioctl.h> //ioctl() and TIOCGWINSZ
#include <unistd.h> // for STDOUT_FILENO
// ...

struct winsize size;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &size);

/* size.ws_row is the number of rows, size.ws_col is the number of columns. */

// ...

Also, while I haven't touched Windows in the last five years, GetConsoleScreenBufferInfo() should help you get the console window size.

OTHER TIPS

On Windows, use the following code to print the size of the console window (borrowed from quantum's answer here):

#include <windows.h>

int main(int argc, char *argv[]) 
{
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    int columns, rows;
  
    GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
    columns = csbi.srWindow.Right - csbi.srWindow.Left + 1;
    rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
  
    printf("columns: %d\n", columns);
    printf("rows: %d\n", rows);
    return 0;
}

On Linux, use the following instead (borrowed from John T's answer here):

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

int main (int argc, char **argv)
{
    struct winsize w;
    ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);

    printf ("lines %d\n", w.ws_row);
    printf ("columns %d\n", w.ws_col);
    return 0;  // make sure your main returns int
}

Here is a solution that works in both Windows and Linux:

#if defined(_WIN32)
#define WIN32_LEAN_AND_MEAN
#define VC_EXTRALEAN
#include <Windows.h>
#elif defined(__linux__)
#include <sys/ioctl.h>
#endif // Windows/Linux

void get_terminal_size(int& width, int& height) {
#if defined(_WIN32)
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi);
    width = (int)(csbi.srWindow.Right-csbi.srWindow.Left+1);
    height = (int)(csbi.srWindow.Bottom-csbi.srWindow.Top+1);
#elif defined(__linux__)
    struct winsize w;
    ioctl(fileno(stdout), TIOCGWINSZ, &w);
    width = (int)(w.ws_col);
    height = (int)(w.ws_row);
#endif // Windows/Linux
}

#include <iostream>
using namespace std;
int main() {
    int width=0, height=0;
    get_terminal_size(width, height);
    cout << "width=" << width << ", height=" << height << endl;
    cin.get();
    return 0;
}

To expand @herohuyongtao answer for Windows. The .srWindow property gives the answer to the size of the console window, i.e. visible rows and cols. This doesn't say what is the actual available screen buffer width and height, which could be larger if window contains scroll bars. If this is the case, use .dwSize:

CONSOLE_SCREEN_BUFFER_INFO sbInfo;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &sbInfo);
int availableColumns = sbInfo.dwSize.X;
int availableRows = sbInfo.dwSize.Y;

On GNU/Linux using libtermcap (https://www.gnu.org/software/termutils/manual/termcap-1.3/html_mono/termcap.html) create demo.c:

#include <stdio.h>
#include <stdlib.h>
#include <curses.h>
#include <term.h>

static char term_buffer[2048];

void
init_terminal_data (void)
{

  char *termtype = getenv ("TERM");
  int success;

  if (termtype == NULL)
    fprintf (stderr, "Specify a terminal type with `setenv TERM <yourtype>'.\n");

  success = tgetent (term_buffer, termtype);
  if (success < 0)
    fprintf (stderr, "Could not access the termcap data base.\n");
  if (success == 0)
    fprintf (stderr, "Terminal type `%s' is not defined.\n", termtype);
}

int
main ()
{
  init_terminal_data ();
  printf ("Got: Lines: %d, Columns: %d\n", tgetnum ("li"), tgetnum ("co"));
  return 0;
}

Then compile with gcc -o demo.x demo.c -ltermcap and run to give:

$ ./demo.x
Got: Lines: 24, Columns: 80

I doubt this helps much on Windows though, I don't know that platform.

(Some of this code is copied straight from the termcap documentation.)

After much grief:

  auto const w(WEXITSTATUS(std::system("exit `tput cols`")));
  auto const h(WEXITSTATUS(std::system("exit `tput lines`")));

As noted by choroba in a comment, you can find the terminal size in shell scripts using stty size.

This works on Linux, and also on macOS (Monterey 12.6.6 tested), and by inference on BSD-based platforms. It is not mandated by POSIX 2018 AFAICT. It prints the screen size as "rows cols" (two numbers separated by white space).

For example, when run in a rather large window (with 65 rows by 207 columns) on a big screen, I got the output:

$ stty size
65 207
$

On both Linux and macOS, stty objects if standard input is not a terminal and writes an error message to standard error (even if, for example, standard error is connected to a terminal). You can work around that with -F /dev/stderr (or another named file) if need be, but you'll still get an error if ioctl(fd, TIOCGWINSZ, &winsz) fails. You may actually find a use for the shell test operator [ -t 0 ] (or 1 or 2) — which tests whether the numbered file descriptor is a terminal.

A deleted answer by hek2gml mentions that you can use:

$ tput lines
65
$ tput cols
207
$

You can only get one number at a time.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top