Porytiles
Loading...
Searching...
No Matches
terminal_width.cpp
Go to the documentation of this file.
2
3#include <cstddef>
4#include <cstdlib>
5#include <optional>
6#include <string>
7
8#include <sys/ioctl.h>
9#include <unistd.h>
10
11namespace {
12
14std::optional<std::size_t> width_from_columns_env()
15{
16 const char *columns = std::getenv("COLUMNS");
17 if (columns == nullptr) {
18 return std::nullopt;
19 }
20 try {
21 std::size_t consumed = 0;
22 const long value = std::stol(std::string{columns}, &consumed);
23 // Require the whole value to parse and to be positive; ignore junk like "abc" or "80x".
24 if (consumed == std::string{columns}.size() && value > 0) {
25 return static_cast<std::size_t>(value);
26 }
27 }
28 catch (...) {
29 // Fall through to the next source on any parse failure.
30 }
31 return std::nullopt;
32}
33
35std::optional<std::size_t> width_from_ioctl(const int fd)
36{
37 struct winsize ws{};
38 if (ioctl(fd, TIOCGWINSZ, &ws) == 0 && ws.ws_col > 0) {
39 return static_cast<std::size_t>(ws.ws_col);
40 }
41 return std::nullopt;
42}
43
44} // namespace
45
46namespace porytiles {
47
48std::size_t resolve_terminal_width(const int fd, const std::size_t fallback)
49{
50 if (const auto from_env = width_from_columns_env()) {
51 return *from_env;
52 }
53 if (const auto from_ioctl = width_from_ioctl(fd)) {
54 return *from_ioctl;
55 }
56 return fallback;
57}
58
59} // namespace porytiles
std::size_t resolve_terminal_width(int fd, std::size_t fallback=80)
Resolves the column width to use for wrapping diagnostic output on fd.