BASIS  r3148
stdio.cxx
Go to the documentation of this file.
00001 /**
00002  * @file  stdio.cxx
00003  * @brief Standard I/O functions.
00004  *
00005  * Copyright (c) 2012 University of Pennsylvania. All rights reserved.<br />
00006  * See https://www.cbica.upenn.edu/sbia/software/license.html or COPYING file.
00007  *
00008  * Contact: SBIA Group <sbia-software at uphs.upenn.edu>
00009  */
00010 
00011 #include <basis/config.h> // WINDOWS macro
00012 #include <basis/assert.h> // assert()
00013 
00014 #include <stdlib.h>       // getenv()
00015 
00016 #if WINDOWS
00017 #  include <windows.h>    // GetConsoleScreenBufferInfo()
00018 #else
00019 #  include <unistd.h>     // STDOUT_FILENO
00020 #  include <sys/ioctl.h>  // ioctl()
00021 #endif
00022 
00023 #include <basis/stdio.h>
00024 
00025 
00026 // acceptable in .cxx file
00027 using namespace std;
00028 
00029 
00030 namespace basis {
00031 
00032 
00033 // ---------------------------------------------------------------------------
00034 void get_terminal_size(int& lines, int& columns)
00035 {
00036     lines   = 0;
00037     columns = 0;
00038     #if WINDOWS
00039         CONSOLE_SCREEN_BUFFER_INFO csbi;
00040         if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &csbi)) {
00041             columns = csbi.dwSize.X;
00042             lines   = csbi.dwSize.Y;
00043         }
00044     #else
00045         struct winsize w;
00046         if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &w) == 0) {
00047             columns = w.ws_col;
00048             lines   = w.ws_row;
00049         }
00050     #endif
00051     if (columns == 0) {
00052         const char* COLUMNS = getenv("COLUMNS");
00053         if (COLUMNS) columns = atoi(COLUMNS);
00054     }
00055     if (lines == 0) {
00056         const char* LINES = getenv("LINES");
00057         if (LINES) columns = atoi(LINES);
00058     }
00059 }
00060 
00061 // ---------------------------------------------------------------------------
00062 int get_terminal_lines()
00063 {
00064     int lines, columns;
00065     get_terminal_size(lines, columns);
00066     return lines;
00067 }
00068 
00069 // ---------------------------------------------------------------------------
00070 int get_terminal_columns()
00071 {
00072     int lines, columns;
00073     get_terminal_size(lines, columns);
00074     return columns;
00075 }
00076 
00077 // ---------------------------------------------------------------------------
00078 ostream& print_wrapped(ostream&      os,
00079                        const string& text,
00080                        int           width,
00081                        int           indent,
00082                        int           offset)
00083 {
00084     assert(indent + offset < width); // such that allowed_length > 0
00085 
00086     int text_length    = static_cast<int>(text.length());
00087     int allowed_length = width - indent;
00088     int start          = 0;
00089 
00090     // Note: Despite of the TCLAP::StdOutput::spacePrint() implementation,
00091     //       the following while loop is always performed even if the given
00092     //       text seems to fit on one line. Reason is that the text can
00093     //       include newline characters itself. In this case, we still need
00094     //       to take care of the proper indentation of the consecutive lines.
00095 
00096     while (start < text_length) {
00097         // determine length of next line to be printed
00098         int line_length = min<int>(text_length - start, allowed_length);
00099         if (line_length == allowed_length) {
00100             while (line_length >= 0 &&
00101                     text[start + line_length] != ' ' && 
00102                     text[start + line_length] != ',' &&
00103                     text[start + line_length] != '|' ) {
00104                 line_length--;
00105             }
00106         }
00107         if (line_length <= 0) line_length = allowed_length;
00108         // truncate line at already present newline (including the newline)
00109         for (int i = 0; i < line_length; i++) {
00110             if (text[start + i] == '\n') line_length = i + 1;
00111         }
00112         // print the line and add a newline
00113         for (int i = 0; i < indent; i++ ) os << " ";
00114         os << text.substr(start, line_length) << endl;
00115         // adjust indent for lines after the first one
00116         if (start == 0) {
00117             indent         += offset;
00118             allowed_length -= offset;
00119         }
00120         // next line
00121         start += line_length;
00122         // skip space characters so next line does not start with
00123         // a further indentation besides the one specified by the indent
00124         while (text[start] == ' ' && start < text_length) start++;
00125     }
00126 
00127     return os;
00128 }
00129 
00130 
00131 } // namespace basis