37

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.

Vittorio Romeo
  • 86,944
  • 30
  • 238
  • 393

6 Answers6

61

On Windows, use the following code to print the size of the console window (borrowed from 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 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
}
herohuyongtao
  • 47,739
  • 25
  • 124
  • 164
  • 3
    Any chance of a cross-platform solution? – Raymond May 22 '19 at 04:25
  • 2
    @Raymond you can do a cross-platform solution by using `#ifdef WIN32`, `#else`, `#endif` lines (or something similar). This applies to both the `#include`s and the `code block`s. – Hybr13 May 03 '22 at 12:48
35

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.

Community
  • 1
  • 1
Moshe Gottlieb
  • 3,792
  • 24
  • 38
6

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;
Killzone Kid
  • 5,980
  • 3
  • 15
  • 34
6

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;
}
ProjectPhysX
  • 3,068
  • 2
  • 11
  • 26
  • 1. There is no iostream or iostream.h in linux. I don't know what that is or if it was needed. Because if so... this is no longer cross platform. 2. There is no such thing as int&. If you meant: ` void get_terminal_size(int &width, int &height) ` that will throw an error. if you meant ` void get_terminal_size(int *width, int *height) ` you get a bunch of warnings and it returns 0,0. This would be great... if it worked :/ – Eric Sebasta Aug 15 '20 at 18:47
  • 4
    @Eric Sebasta of course there is the standard library in Linux C++. For the `get_terminal_size(...)` call you don't need it, it's just for demonstrating the use of it and printing the results in the console. What compiler are you using? Try compiling with g++. `int&` is a pass-by-reference, which is a standard thing in C++. If for some reason this does not work for you, try with pointers: `get_terminal_size(int* width, int* height)` and replace every `width = ` and `height = ` by `*width = ` and `*height = `. – ProjectPhysX Aug 16 '20 at 09:39
2

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.)

Andrew
  • 2,769
  • 14
  • 19
1

After much grief:

  auto const w(WEXITSTATUS(std::system("exit `tput cols`")));
  auto const h(WEXITSTATUS(std::system("exit `tput lines`")));
user1095108
  • 13,350
  • 9
  • 53
  • 103