]> git.cworth.org Git - vogl/blob - src/voglcore/vogl_console.cpp
Initial vogl checkin
[vogl] / src / voglcore / vogl_console.cpp
1 /**************************************************************************
2  *
3  * Copyright 2013-2014 RAD Game Tools and Valve Software
4  * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
5  * All Rights Reserved.
6  *
7  * Permission is hereby granted, free of charge, to any person obtaining a copy
8  * of this software and associated documentation files (the "Software"), to deal
9  * in the Software without restriction, including without limitation the rights
10  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11  * copies of the Software, and to permit persons to whom the Software is
12  * furnished to do so, subject to the following conditions:
13  *
14  * The above copyright notice and this permission notice shall be included in
15  * all copies or substantial portions of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23  * THE SOFTWARE.
24  *
25  **************************************************************************/
26
27 // File: vogl_console.cpp
28 #include "vogl_core.h"
29 #include "vogl_console.h"
30 #include "vogl_data_stream.h"
31 #include "vogl_threading.h"
32 #include "vogl_command_line_params.h"
33 #include "vogl_strutils.h"
34
35 #ifdef WIN32
36 #include <tchar.h>
37 #include <conio.h>
38 #endif
39
40 #if VOGL_USE_LINUX_API
41 #include <termios.h>
42 #include <unistd.h>
43 #include <sys/select.h>
44 #include <stropts.h>
45 #include <sys/ioctl.h>
46 #endif
47
48 namespace vogl
49 {
50     static const char *s_msgnames[cCMTTotal] =
51         {
52           "Debug",
53           "Progress",
54           "Info",
55           "Default",
56           "Message",
57           "Warning",
58           "Error",
59           "Header1",
60         };
61
62     eConsoleMessageType console::m_default_category = cInfoConsoleMessage;
63     uint console::m_num_output_funcs;
64     console::console_func console::m_output_funcs[cMaxOutputFuncs];
65     bool console::m_prefixes = true;
66     bool console::m_output_disabled;
67     data_stream *console::m_pLog_stream;
68     mutex *console::m_pMutex;
69     uint console::m_num_messages[cCMTTotal];
70     bool console::m_at_beginning_of_line = true;
71     char console::m_tool_prefix[256];
72
73     const uint cConsoleBufSize = 256 * 1024;
74
75     void console::init()
76     {
77         if (!m_pMutex)
78         {
79             m_pMutex = vogl_new(mutex);
80         }
81     }
82
83     void console::deinit()
84     {
85         if (m_pMutex)
86         {
87             vogl_delete(m_pMutex);
88             m_pMutex = NULL;
89         }
90
91         m_num_output_funcs = 0;
92     }
93
94     const char *console::get_message_type_str(eConsoleMessageType type)
95     {
96         if (type >= 0 && (type < VOGL_ARRAY_SIZE(s_msgnames)))
97             return s_msgnames[type];
98         return "??";
99     }
100
101     eConsoleMessageType console::get_message_type_from_str(const char *str)
102     {
103         dynamic_string msgname = str;
104
105         for (uint type = 0; type < VOGL_ARRAY_SIZE(s_msgnames); type++)
106         {
107             if (msgname.compare(s_msgnames[type], false) == 0)
108                 return (eConsoleMessageType)type;
109         }
110         return (eConsoleMessageType)-1;
111     }
112
113     void console::vprintf(eConsoleMessageType type, const char *p, va_list args)
114     {
115         init();
116
117         if (m_pMutex)
118             m_pMutex->lock();
119
120         m_num_messages[type]++;
121
122         static char buf[cConsoleBufSize];
123
124         char *pDst = buf;
125         uint buf_left = sizeof(buf);
126
127         if ((m_prefixes) && (m_at_beginning_of_line))
128         {
129             if (m_tool_prefix[0])
130             {
131                 size_t l = strlen(m_tool_prefix);
132                 memcpy(pDst, m_tool_prefix, l);
133                 pDst += l;
134                 buf_left -= l;
135             }
136
137             const char *pPrefix = NULL;
138             switch (type)
139             {
140                 case cDebugConsoleMessage:
141                     pPrefix = "Debug: ";
142                     break;
143                 case cWarningConsoleMessage:
144                     pPrefix = "Warning: ";
145                     break;
146                 case cErrorConsoleMessage:
147                     pPrefix = "Error: ";
148                     break;
149                 default:
150                     break;
151             }
152
153             if (pPrefix)
154             {
155                 size_t l = strlen(pPrefix);
156                 memcpy(pDst, pPrefix, l);
157                 pDst += l;
158                 buf_left -= l;
159             }
160         }
161
162         vogl::vogl_vsprintf_s(pDst, buf_left, p, args);
163
164         bool handled = false;
165
166         if (m_num_output_funcs)
167         {
168             for (uint i = 0; i < m_num_output_funcs; i++)
169                 if (m_output_funcs[i].m_func(type, buf, m_output_funcs[i].m_pData))
170                     handled = true;
171         }
172
173         if ((!m_output_disabled) && (!handled))
174         {
175             FILE *pFile = (type == cErrorConsoleMessage) ? stderr : stdout;
176
177             fputs(buf, pFile);
178         }
179
180         uint n = static_cast<uint>(strlen(buf));
181         m_at_beginning_of_line = (n) && (buf[n - 1] == '\n');
182
183         if ((type != cProgressConsoleMessage) && (m_pLog_stream))
184         {
185             // Yes this is bad.
186             dynamic_string tmp_buf(buf);
187
188             tmp_buf.translate_lf_to_crlf();
189
190             m_pLog_stream->printf("%s", tmp_buf.get_ptr());
191             m_pLog_stream->flush();
192         }
193
194         if (m_pMutex)
195             m_pMutex->unlock();
196     }
197
198     void console::printf(eConsoleMessageType type, const char *p, ...)
199     {
200         va_list args;
201         va_start(args, p);
202         vprintf(type, p, args);
203         va_end(args);
204     }
205
206     void console::printf(const char *p, ...)
207     {
208         va_list args;
209         va_start(args, p);
210         vprintf(m_default_category, p, args);
211         va_end(args);
212     }
213
214     void console::set_default_category(eConsoleMessageType category)
215     {
216         init();
217
218         m_default_category = category;
219     }
220
221     eConsoleMessageType console::get_default_category()
222     {
223         init();
224
225         return m_default_category;
226     }
227
228     void console::add_console_output_func(console_output_func pFunc, void *pData)
229     {
230         init();
231
232         if (m_pMutex)
233             m_pMutex->lock();
234
235         VOGL_ASSERT(m_num_output_funcs < cMaxOutputFuncs);
236
237         if (m_num_output_funcs < cMaxOutputFuncs)
238         {
239             m_output_funcs[m_num_output_funcs++] = console_func(pFunc, pData);
240         }
241
242         if (m_pMutex)
243             m_pMutex->unlock();
244     }
245
246     void console::remove_console_output_func(console_output_func pFunc)
247     {
248         init();
249
250         if (m_pMutex)
251             m_pMutex->lock();
252
253         for (int i = m_num_output_funcs - 1; i >= 0; i--)
254         {
255             if (m_output_funcs[i].m_func == pFunc)
256             {
257                 m_output_funcs[i] = m_output_funcs[m_num_output_funcs - 1];
258                 m_num_output_funcs--;
259             }
260         }
261
262         if (m_pMutex)
263             m_pMutex->unlock();
264     }
265
266 #define MESSAGE_VPRINTF_IMPL(_msgtype) \
267         va_list args; \
268         va_start(args, p); \
269         vprintf(_msgtype, p, args); \
270         va_end(args)
271
272     void console::progress(const char *p, ...) { MESSAGE_VPRINTF_IMPL(cProgressConsoleMessage); }
273     void console::info(const char *p, ...) { MESSAGE_VPRINTF_IMPL(cInfoConsoleMessage); }
274     void console::message(const char *p, ...) { MESSAGE_VPRINTF_IMPL(cMessageConsoleMessage); }
275     void console::cons(const char *p, ...) { MESSAGE_VPRINTF_IMPL(cConsoleConsoleMessage); }
276     void console::debug(const char *p, ...) { MESSAGE_VPRINTF_IMPL(cDebugConsoleMessage); }
277     void console::warning(const char *p, ...) { MESSAGE_VPRINTF_IMPL(cWarningConsoleMessage); }
278     void console::error(const char *p, ...) { MESSAGE_VPRINTF_IMPL(cErrorConsoleMessage); }
279     void console::header1(const char *p, ...) { MESSAGE_VPRINTF_IMPL(cHeader1ConsoleMessage); }
280
281 #undef MESSAGE_VPRINTF_IMPL
282     
283 #if VOGL_USE_WIN32_API
284     int vogl_getch()
285     {
286         return _getch();
287     }
288
289     int vogl_kbhit()
290     {
291         return _kbhit();
292     }
293 #elif VOGL_USE_LINUX_API
294     int vogl_getch()
295     {
296         struct termios oldt, newt;
297         int ch;
298         tcgetattr(STDIN_FILENO, &oldt);
299         newt = oldt;
300         newt.c_lflag &= ~(ICANON | ECHO);
301         tcsetattr(STDIN_FILENO, TCSANOW, &newt);
302         ch = getchar();
303         tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
304         return ch;
305     }
306
307     // See http://www.flipcode.com/archives/_kbhit_for_Linux.shtml
308     int vogl_kbhit()
309     {
310         static const int STDIN = 0;
311         static bool initialized = false;
312
313         if (!initialized)
314         {
315             // Use termios to turn off line buffering
316             termios term;
317             tcgetattr(STDIN, &term);
318             term.c_lflag &= ~ICANON;
319             tcsetattr(STDIN, TCSANOW, &term);
320             setbuf(stdin, NULL);
321             initialized = true;
322         }
323
324         int bytesWaiting;
325         ioctl(STDIN, FIONREAD, &bytesWaiting);
326         return bytesWaiting;
327     }
328 #else
329     int vogl_getch()
330     {
331         VOGL_ASSERT_ALWAYS;
332         printf("Unimplemented!\n");
333         return 0;
334     }
335
336     int vogl_kbhit()
337     {
338         VOGL_ASSERT_ALWAYS;
339         printf("Unimplemented!\n");
340         return 0;
341     }
342 #endif
343
344 } // namespace vogl