stdio.cxx
Go to the documentation of this file.
1 // ============================================================================
2 // Copyright (c) 2011-2012 University of Pennsylvania
3 // Copyright (c) 2013-2016 Andreas Schuh
4 // All rights reserved.
5 //
6 // See COPYING file for license information or visit
7 // https://cmake-basis.github.io/download.html#license
8 // ============================================================================
9 
10 /**
11  * @file stdio.cxx
12  * @brief Standard I/O functions.
13  */
14 
15 #include <basis/config.h> // WINDOWS macro
16 #include <basis/assert.h> // assert()
17 
18 #include <algorithm> // min<T>()
19 #include <stdlib.h> // getenv()
20 
21 #if WINDOWS
22 # include <windows.h> // GetConsoleScreenBufferInfo()
23 #else
24 # include <unistd.h> // STDOUT_FILENO
25 # include <sys/ioctl.h> // ioctl()
26 #endif
27 
28 #include <basis/stdio.h>
29 
30 
31 // acceptable in .cxx file
32 using namespace std;
33 
34 
35 namespace basis {
36 
37 
38 // ---------------------------------------------------------------------------
39 void get_terminal_size(int& lines, int& columns)
40 {
41  lines = 0;
42  columns = 0;
43  #if WINDOWS
44  CONSOLE_SCREEN_BUFFER_INFO csbi;
45  if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
46  columns = csbi.dwSize.X;
47  lines = csbi.dwSize.Y;
48  }
49  if (columns == 0) {
50  char* COLUMNS;
51  size_t sz;
52  if (_dupenv_s(&COLUMNS, &sz, "COLUMNS") == 0 && COLUMNS) {
53  columns = atoi(COLUMNS);
54  free(COLUMNS);
55  }
56  }
57  if (lines == 0) {
58  char* LINES;
59  size_t sz;
60  if (_dupenv_s(&LINES, &sz, "LINES") == 0 && LINES) {
61  columns = atoi(LINES);
62  free(LINES);
63  }
64  }
65  #else
66  struct winsize w;
67  if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == 0) {
68  columns = w.ws_col;
69  lines = w.ws_row;
70  }
71  if (columns == 0) {
72  const char* COLUMNS = getenv("COLUMNS");
73  if (COLUMNS) columns = atoi(COLUMNS);
74  }
75  if (lines == 0) {
76  const char* LINES = getenv("LINES");
77  if (LINES) columns = atoi(LINES);
78  }
79  #endif
80 }
81 
82 // ---------------------------------------------------------------------------
84 {
85  int lines, columns;
86  get_terminal_size(lines, columns);
87  return lines;
88 }
89 
90 // ---------------------------------------------------------------------------
92 {
93  int lines, columns;
94  get_terminal_size(lines, columns);
95  return columns;
96 }
97 
98 // ---------------------------------------------------------------------------
99 ostream& print_wrapped(ostream& os,
100  const string& text,
101  int width,
102  int indent,
103  int offset)
104 {
105  assert(indent + offset < width); // such that allowed_length > 0
106 
107  int text_length = static_cast<int>(text.length());
108  int allowed_length = width - indent;
109  int start = 0;
110 
111  // Note: Despite of the TCLAP::StdOutput::spacePrint() implementation,
112  // the following while loop is always performed even if the given
113  // text seems to fit on one line. Reason is that the text can
114  // include newline characters itself. In this case, we still need
115  // to take care of the proper indentation of the consecutive lines.
116 
117  while (start < text_length) {
118  // determine length of next line to be printed
119  int line_length = min<int>(text_length - start, allowed_length);
120  if (line_length == allowed_length) {
121  while (line_length >= 0 &&
122  text[start + line_length] != ' ' &&
123  text[start + line_length] != ',' &&
124  text[start + line_length] != '|' ) {
125  line_length--;
126  }
127  }
128  if (line_length <= 0) line_length = allowed_length;
129  // truncate line at already present newline (including the newline)
130  for (int i = 0; i < line_length; i++) {
131  if (text[start + i] == '\n') line_length = i + 1;
132  }
133  // print the line and add a newline
134  for (int i = 0; i < indent; i++ ) os << " ";
135  os << text.substr(start, line_length) << endl;
136  // adjust indent for lines after the first one
137  if (start == 0) {
138  indent += offset;
139  allowed_length -= offset;
140  }
141  // next line
142  start += line_length;
143  // skip space characters so next line does not start with
144  // a further indentation besides the one specified by the indent
145  while (text[start] == ' ' && start < text_length) start++;
146  }
147 
148  return os;
149 }
150 
151 
152 } // namespace basis
void get_terminal_size(int &lines, int &columns)
Get size of terminal window.
Definition: stdio.cxx:39
#define assert(condition)
Assertion without custom message.
Definition: assert.h:44
System related macro definitions.
STL namespace.
Definition: basis.h:34
Defines macros used for assertions.
int get_terminal_lines()
Get maximum number of lines of terminal window.
Definition: stdio.cxx:83
std::ostream & print_wrapped(std::ostream &os, const std::string &text, int width, int indent, int offset)
Print text, wrapped at a fixed maximum number of columns.
Definition: stdio.cxx:99
Standard I/O functions.
int get_terminal_columns()
Get maximum number of columns of terminal window.
Definition: stdio.cxx:91