1 // ----------------------------------------------------------------------------
2 // -                        Open3D: www.open3d.org                            -
3 // ----------------------------------------------------------------------------
4 // The MIT License (MIT)
5 //
6 // Copyright (c) 2018 www.open3d.org
7 //
8 // Permission is hereby granted, free of charge, to any person obtaining a copy
9 // of this software and associated documentation files (the "Software"), to deal
10 // in the Software without restriction, including without limitation the rights
11 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 // copies of the Software, and to permit persons to whom the Software is
13 // furnished to do so, subject to the following conditions:
14 //
15 // The above copyright notice and this permission notice shall be included in
16 // all copies or substantial portions of the Software.
17 //
18 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23 // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24 // IN THE SOFTWARE.
25 // ----------------------------------------------------------------------------
26 
27 #include "Console.h"
28 
29 #include <cstdio>
30 #include <cstdarg>
31 #include <cstdlib>
32 #include <string>
33 #include <ctime>
34 #include <algorithm>
35 #include <climits>
36 #include <cmath>
37 #include <cstdint>
38 #include <cerrno>
39 #ifdef _WIN32
40 #include <windows.h>
41 #endif
42 
43 #include <Core/Utility/Helper.h>
44 
45 namespace three{
46 
47 namespace {
48 
49 enum class TextColor {
50     Black = 0,
51     Red = 1,
52     Green = 2,
53     Yellow = 3,
54     Blue = 4,
55     Magenta = 5,
56     Cyan = 6,
57     White = 7
58 };
59 
60 static VerbosityLevel global_verbosity_level = VerbosityLevel::VerboseInfo;
61 
62 /// Internal function to change text color for the console
63 /// Note there is no security check for parameters.
64 /// \param text_color, from 0 to 7, they are black, red, green, yellow, blue,
65 /// magenta, cyan, white
66 /// \param emphasis_text is 0 or 1
ChangeConsoleColor(TextColor text_color,int highlight_text)67 void ChangeConsoleColor(TextColor text_color, int highlight_text)
68 {
69 #ifdef _WIN32
70     const WORD EMPHASIS_MASK[2] = { 0, FOREGROUND_INTENSITY };
71     const WORD COLOR_MASK[8] = {
72         0,
73         FOREGROUND_RED,
74         FOREGROUND_GREEN,
75         FOREGROUND_GREEN | FOREGROUND_RED,
76         FOREGROUND_BLUE,
77         FOREGROUND_RED | FOREGROUND_BLUE,
78         FOREGROUND_GREEN | FOREGROUND_BLUE,
79         FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED
80     };
81     HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
82     SetConsoleTextAttribute(h,
83             EMPHASIS_MASK[highlight_text] | COLOR_MASK[(int)text_color]);
84 #else
85     printf("%c[%d;%dm", 0x1B, highlight_text, (int)text_color + 30);
86 #endif
87 }
88 
ResetConsoleColor()89 void ResetConsoleColor()
90 {
91 #ifdef _WIN32
92     HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE);
93     SetConsoleTextAttribute(h,
94             FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED);
95 #else
96     printf("%c[0;m", 0x1B);
97 #endif
98 }
99 
100 static int64_t expected_console_count = 0;
101 
102 static int64_t current_console_progress = 0;
103 
104 static int current_console_progress_pixel = 0;
105 
106 static std::string console_progress_info = "";
107 
108 static const int CONSOLE_PROGRESS_RESOLUTION = 40;
109 
PrintConsoleProgress()110 void PrintConsoleProgress()
111 {
112     if (current_console_progress == expected_console_count) {
113         PrintInfo("%s[%s] 100%%\n", console_progress_info.c_str(),
114                 std::string(CONSOLE_PROGRESS_RESOLUTION, '=').c_str());
115     } else {
116         int new_console_progress_pixel = int(current_console_progress *
117                 CONSOLE_PROGRESS_RESOLUTION / expected_console_count);
118         if (new_console_progress_pixel > current_console_progress_pixel) {
119             current_console_progress_pixel = new_console_progress_pixel;
120             int percent = int(current_console_progress *
121                     100 / expected_console_count);
122             PrintInfo("%s[%s>%s] %d%%\r", console_progress_info.c_str(),
123                     std::string(current_console_progress_pixel, '=').c_str(),
124                     std::string(CONSOLE_PROGRESS_RESOLUTION - 1 -
125                     current_console_progress_pixel, ' ').c_str(),
126                     percent);
127             fflush(stdout);
128         }
129     }
130 }
131 
132 }    // unnamed namespace
133 
SetVerbosityLevel(VerbosityLevel verbosity_level)134 void SetVerbosityLevel(VerbosityLevel verbosity_level)
135 {
136     global_verbosity_level = verbosity_level;
137 }
138 
GetVerbosityLevel()139 VerbosityLevel GetVerbosityLevel()
140 {
141     return global_verbosity_level;
142 }
143 
PrintError(const char * format,...)144 void PrintError(const char *format, ...)
145 {
146     if (global_verbosity_level >= VerbosityLevel::VerboseError) {
147         ChangeConsoleColor(TextColor::Red, 1);
148         va_list args;
149         va_start(args, format);
150         vprintf(format, args);
151         va_end(args);
152         ResetConsoleColor();
153     }
154 }
155 
PrintWarning(const char * format,...)156 void PrintWarning(const char *format, ...)
157 {
158     if (global_verbosity_level >= VerbosityLevel::VerboseWarning) {
159         ChangeConsoleColor(TextColor::Yellow, 1);
160         va_list args;
161         va_start(args, format);
162         vprintf(format, args);
163         va_end(args);
164         ResetConsoleColor();
165     }
166 }
167 
PrintInfo(const char * format,...)168 void PrintInfo(const char *format, ...)
169 {
170     if (global_verbosity_level >= VerbosityLevel::VerboseInfo) {
171         va_list args;
172         va_start(args, format);
173         vprintf(format, args);
174         va_end(args);
175     }
176 }
177 
PrintDebug(const char * format,...)178 void PrintDebug(const char *format, ...)
179 {
180     if (global_verbosity_level >= VerbosityLevel::VerboseDebug) {
181         ChangeConsoleColor(TextColor::Green, 0);
182         va_list args;
183         va_start(args, format);
184         vprintf(format, args);
185         va_end(args);
186         ResetConsoleColor();
187     }
188 }
189 
PrintAlways(const char * format,...)190 void PrintAlways(const char *format, ...)
191 {
192     if (global_verbosity_level >= VerbosityLevel::VerboseAlways) {
193         ChangeConsoleColor(TextColor::Blue, 0);
194         va_list args;
195         va_start(args, format);
196         vprintf(format, args);
197         va_end(args);
198         ResetConsoleColor();
199     }
200 }
201 
ResetConsoleProgress(const int64_t expected_count,const std::string & progress_info)202 void ResetConsoleProgress(const int64_t expected_count,
203         const std::string &progress_info/* = ""*/)
204 {
205     if (expected_count > 0) {
206         expected_console_count = expected_count;
207         current_console_progress = 0;
208     } else {
209         expected_console_count = 1;
210         current_console_progress = 1;
211     }
212     current_console_progress_pixel = -1;
213     console_progress_info = progress_info;
214     PrintConsoleProgress();
215 }
216 
AdvanceConsoleProgress()217 void AdvanceConsoleProgress()
218 {
219     current_console_progress++;
220     PrintConsoleProgress();
221 }
222 
GetCurrentTimeStamp()223 std::string GetCurrentTimeStamp()
224 {
225     time_t rawtime;
226     struct tm *timeinfo;
227     char buffer[DEFAULT_IO_BUFFER_SIZE];
228     time(&rawtime);
229     timeinfo = localtime(&rawtime);
230     strftime(buffer, DEFAULT_IO_BUFFER_SIZE, "%Y-%m-%d-%H-%M-%S", timeinfo);
231     return std::string(buffer);
232 }
233 
GetProgramOptionAsString(int argc,char ** argv,const std::string & option,const std::string & default_value)234 std::string GetProgramOptionAsString(int argc, char **argv,
235         const std::string &option, const std::string &default_value/* = ""*/)
236 {
237     char **itr = std::find(argv, argv + argc, option);
238     if (itr != argv + argc && ++itr != argv + argc) {
239         return std::string(*itr);
240     }
241     return default_value;
242 }
243 
GetProgramOptionAsInt(int argc,char ** argv,const std::string & option,const int default_value)244 int GetProgramOptionAsInt(int argc, char **argv,
245         const std::string &option, const int default_value/* = 0*/)
246 {
247     std::string str = GetProgramOptionAsString(argc, argv, option, "");
248     if (str.length() == 0) {
249         return default_value;
250     }
251     char *end;
252     errno = 0;
253     long l = std::strtol(str.c_str(), &end, 0);
254     if ((errno == ERANGE && l == LONG_MAX) || l > INT_MAX) {
255         return default_value;
256     } else if ((errno == ERANGE && l == LONG_MIN) || l < INT_MIN) {
257         return default_value;
258     } else if (*end != '\0') {
259         return default_value;
260     }
261     return (int)l;
262 }
263 
GetProgramOptionAsDouble(int argc,char ** argv,const std::string & option,const double default_value)264 double GetProgramOptionAsDouble(int argc, char **argv,
265         const std::string &option, const double default_value/* = 0.0*/)
266 {
267     std::string str = GetProgramOptionAsString(argc, argv, option, "");
268     if (str.length() == 0) {
269         return default_value;
270     }
271     char *end;
272     errno = 0;
273     double l = std::strtod(str.c_str(), &end);
274     if (errno == ERANGE && (l == HUGE_VAL || l == -HUGE_VAL)) {
275         return default_value;
276     } else if (*end != '\0') {
277         return default_value;
278     }
279     return l;
280 }
281 
GetProgramOptionAsEigenVectorXd(int argc,char ** argv,const std::string & option,const Eigen::VectorXd default_value)282 Eigen::VectorXd GetProgramOptionAsEigenVectorXd(int argc, char **argv,
283         const std::string &option, const Eigen::VectorXd default_value/* =
284         Eigen::VectorXd::Zero()*/)
285 {
286     std::string str = GetProgramOptionAsString(argc, argv, option, "");
287     if (str.length() == 0 || (!(str.front() == '(' && str.back() == ')') &&
288             !(str.front() == '[' && str.back() == ']') &&
289             !(str.front() == '<' && str.back() == '>'))) {
290         return default_value;
291     }
292     std::vector<std::string> tokens;
293     SplitString(tokens, str.substr(1, str.length() - 2), ",");
294     Eigen::VectorXd vec(tokens.size());
295     for (auto i = 0; i < tokens.size(); i++) {
296         char *end;
297         errno = 0;
298         double l = std::strtod(tokens[i].c_str(), &end);
299         if (errno == ERANGE && (l == HUGE_VAL || l == -HUGE_VAL)) {
300             return default_value;
301         } else if (*end != '\0') {
302             return default_value;
303         }
304         vec(i) = l;
305     }
306     return vec;
307 }
308 
ProgramOptionExists(int argc,char ** argv,const std::string & option)309 bool ProgramOptionExists(int argc, char **argv, const std::string &option)
310 {
311     return std::find(argv, argv + argc, option) != argv + argc;
312 }
313 
ProgramOptionExistsAny(int argc,char ** argv,const std::vector<std::string> & options)314 bool ProgramOptionExistsAny(int argc, char **argv,
315         const std::vector<std::string> &options)
316 {
317     for (const auto &option : options) {
318         if (ProgramOptionExists(argc, argv, option)) {
319             return true;
320         }
321     }
322     return false;
323 }
324 
325 }    // namespace three
326