C++ Utils
0.1
|
00001 00036 #ifndef UTILS_PROGRESS_H 00037 #define UTILS_PROGRESS_H 00038 00039 #include "utils/env.h" 00040 #include "utils/logger.h" 00041 #include "utils/stringutils.h" 00042 00043 #include <fstream> 00044 #include <iomanip> 00045 #include <iostream> 00046 #include <string> 00047 #include <unistd.h> 00048 #include <sys/ioctl.h> 00049 00050 namespace utils 00051 { 00052 00053 // TODO replace this with constexpr in C++11 00054 #define ROTATION_IND "-\\|/" 00055 00056 class Progress 00057 { 00058 private: 00059 enum OutputType 00060 { 00061 DISABLED, 00062 TTY 00063 // TODO Support file output 00064 }; 00065 00066 private: 00068 std::ostream *m_output; 00069 00070 OutputType m_type; 00071 00073 unsigned long m_total; 00074 00076 unsigned long m_current; 00077 00079 unsigned long m_barSize; 00080 00082 unsigned char m_rotPosition; 00083 00085 std::ofstream m_tty; 00086 00087 public: 00088 Progress(unsigned long total = 100) 00089 : m_current(0), m_barSize(80) /* Default size */, m_rotPosition(0) 00090 { 00091 std::string envOutput = Env::get<std::string>("UTILS_PROGRESS_OUTPUT", "STDERR"); 00092 00093 StringUtils::toUpper(envOutput); 00094 00095 if (envOutput == "STDOUT") { 00096 m_output = &std::cout; 00097 m_type = TTY; 00098 00099 setSize(isatty(fileno(stdout))); 00100 } else if (envOutput == "STDERR") { 00101 m_output = &std::cerr; 00102 m_type = TTY; 00103 00104 setSize(isatty(fileno(stderr))); 00105 } else if (envOutput == "TTY") { 00106 m_tty.open("/dev/tty"); // try unix 00107 if (!m_tty) 00108 m_tty.open("CON:"); // try windows 00109 00110 if (m_tty) { 00111 m_output = &m_tty; 00112 m_type = TTY; 00113 setSize(); 00114 } else { 00115 logWarning() << "Could not open terminal. Disabling progress bar."; 00116 m_type = DISABLED; 00117 } 00118 } else { 00119 m_type = DISABLED; 00120 } 00121 } 00122 00127 void setTotal(unsigned long total) 00128 { 00129 m_total = total; 00130 } 00131 00135 void set(unsigned long current) 00136 { 00137 m_current = std::min(current, m_total); 00138 } 00139 00146 void update(unsigned long current) 00147 { 00148 set(current); 00149 00150 if (m_type == DISABLED) 00151 return; 00152 00153 // Calculuate the ratio of complete-to-incomplete. 00154 const float ratio = m_current/static_cast<float>(m_total); 00155 00156 // Show the percentage complete 00157 (*m_output) << std::setw(3) << (int)(ratio*100) << "% ["; 00158 00159 // real width (without additional chars) 00160 const unsigned long realSize = m_barSize - 9; 00161 00162 const unsigned long comChars = realSize * ratio; 00163 00164 // Show the load bar 00165 for (unsigned int i = 0; i < comChars; i++) 00166 (*m_output) << '='; 00167 00168 for (unsigned int i = comChars; i < realSize; i++) 00169 (*m_output) << ' '; 00170 00171 (*m_output) << "] "; 00172 00173 // Print rotation indicator 00174 (*m_output) << ROTATION_IND[m_rotPosition]; 00175 m_rotPosition = (m_rotPosition+1) % 4; 00176 00177 // go to the beginning of the line 00178 (*m_output) << '\r' << std::flush; 00179 } 00180 00184 void update() 00185 { 00186 update(m_current); 00187 } 00188 00192 void increment() 00193 { 00194 update(m_current + 1); 00195 } 00196 00200 void clear() 00201 { 00202 if (m_type == DISABLED) 00203 return; 00204 00205 for (unsigned int i = 0; i < m_barSize; i++) 00206 (*m_output) << ' '; 00207 (*m_output) << '\r' << std::flush; 00208 } 00209 00210 private: 00214 void setSize(bool automatic = true) 00215 { 00216 // Check if size is set in env 00217 unsigned long size = Env::get<unsigned long>("UTILS_PROGRESS_SIZE", 0); 00218 00219 if (size > 0) { 00220 m_barSize = size; 00221 return; 00222 } 00223 00224 if (!automatic) 00225 // No automatic size detection (e.g. for stdout) 00226 return; 00227 00228 // Try to get terminal size 00229 #ifdef TIOCGSIZE 00230 struct ttysize ts; 00231 ioctl(STDIN_FILENO, TIOCGSIZE, &ts); 00232 m_barSize = ts.ts_cols; 00233 #elif defined(TIOCGWINSZ) 00234 struct winsize ts; 00235 ioctl(STDIN_FILENO, TIOCGWINSZ, &ts); 00236 m_barSize = ts.ws_col; 00237 #else 00238 logWarning() << "Could not get terminal size, using default"; 00239 #endif 00240 } 00241 }; 00242 00243 } 00244 00245 #endif // UTILS_PROGRESS_H