2

I have a function which prints some text to an ostream& it receives. I would like to make it adapt to the terminal width, if the ostream targets a terminal, and otherwise default to some value.

What I do right now is the following:

  1. Get an ofstream from the ostream.
  2. Get a FILE* from the ofstream.
  3. Get an integer file descriptor from the FILE*.
  4. Do ioctl(file_descriptor, TIOCGWINSZ, &my_struct_winsize);

with steps 1 and 2 bring due to this SO answer:

Getting a FILE* from a std::fstream

but they are non-portable and GCC-specific (and I'm not sure they'll work for ostreams other than cout/cerr/cin). Can I do better than this?

Community
  • 1
  • 1
einpoklum
  • 118,144
  • 57
  • 340
  • 684
  • 1
    I think I would involve the user. If no user spec then I think I'd check out some terminal database. In the 80's or therabouts it was, as I recall, "termcap". – Cheers and hth. - Alf Feb 27 '16 at 10:42
  • @Cheersandhth.-Alf: That's not the issue, i.e. I don't mind checking a DB - but what should I look up in that DB? Remember I only get an ostream. – einpoklum Feb 27 '16 at 10:43
  • how about using ncurses? – Non-maskable Interrupt Feb 27 '16 at 10:46
  • @einpoklum Correct me if I'm wrong, but my thinking was that if/when you identify the stream as a tty (_isatty in Windows, but you're in Unixland, yes?), then there is only one relevant terminal, the one identified by terminal environment variable? – Cheers and hth. - Alf Feb 27 '16 at 10:46
  • @Calvin: I know ncurses exists, and IIRC it's a C library. Can you be more specific regarding what I should do with it? – einpoklum Feb 27 '16 at 10:48
  • @Cheersandhth.-Alf: I am i Unixland (although Windows can also be Unixland with some effort). I wanted to make my question more general than your assumption, but for the sake of discussion assume you're right. Still, on my system, the value of `TERM` is `xterm`. How does that help me determine the width? – einpoklum Feb 27 '16 at 10:50
  • @einpoklum Google ncurses terminal size give you tons of example. If you have trouble using ncurses you may as well edit your question. – Non-maskable Interrupt Feb 27 '16 at 11:11
  • Possible duplicate of [Getting terminal width in C?](http://stackoverflow.com/questions/1022957/getting-terminal-width-in-c) – Thomas Dickey Feb 27 '16 at 13:05
  • @ThomasDickey: No, that question is about C, I'm asking about C++, note the tags. – einpoklum Feb 27 '16 at 13:06
  • Any C++ application can (and usually *does*) call libraries written in C. – Thomas Dickey Feb 27 '16 at 13:08
  • @ThomasDickey: It's still not what I asked. Saying "do it like you would in C" is just one answer. – einpoklum Feb 27 '16 at 16:32

1 Answers1

1

None of that is gcc-specific. For the rest, TIOCGWINSZ is widely implemented and used with POSIX termios (terminal I/O), although it and the corresponding SIGWINCH are oddly enough not in POSIX. Other methods of getting terminal width (still for POSIX platforms, not generally applicable to Windows):

  • testing environment variables COLUMNS and LINES (many terminal applications, including those using curses do this, e.g., see use_env, provided by any X/Open curses implementation such as ncurses).
  • using ECMA-48 cursor position report as done by the resize program.

For Windows, none of that applies. You would get the information from one of the Console API calls such as GetConsoleScreenBufferInfo. Cygwin is a special case, because it runs (more or less) POSIX-like applications which work with the ioctl as well as POSIX terminal I/O. MinGW is lower-level, and does not provide any real extension to the Console API in this area.

Further reading:

Thomas Dickey
  • 51,086
  • 7
  • 70
  • 105