3ec56785685ee29191c1e687d4e1b8a423c85a63
[geeqie.git] / src / debug.cc
1 /*
2  * Copyright (C) 2008 - 2016 The Geeqie Team
3  *
4  * Authors: Vladimir Nadvornik, Laurent Monin
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 #include "main.h"
22 #include "debug.h"
23
24 #include "logwindow.h"
25 #include "ui-fileops.h"
26
27 #include <regex.h>
28
29 /*
30  * Logging functions
31  */
32 static gchar *regexp = NULL;
33
34 static gboolean log_msg_cb(gpointer data)
35 {
36         gchar *buf = data;
37         log_window_append(buf, LOG_MSG);
38         g_free(buf);
39         return FALSE;
40 }
41
42 /**
43  * @brief Appends a user information message to the log window queue
44  * @param data The message
45  * @returns FALSE
46  * 
47  * If the first word of the message is either "error" or "warning"
48  * (case insensitive) the message is color-coded appropriately
49  */
50 static gboolean log_normal_cb(gpointer data)
51 {
52         gchar *buf = data;
53         gchar *buf_casefold = g_utf8_casefold(buf, -1);
54         gchar *error_casefold = g_utf8_casefold(_("error"), -1);
55         gchar *warning_casefold = g_utf8_casefold(_("warning"), -1);
56
57         if (buf_casefold == g_strstr_len(buf_casefold, -1, error_casefold))
58                 {
59                 log_window_append(buf, LOG_ERROR);
60                 }
61         else if (buf_casefold == g_strstr_len(buf_casefold, -1, warning_casefold))
62                 {
63                 log_window_append(buf, LOG_WARN);
64                 }
65         else
66                 {
67                 log_window_append(buf, LOG_NORMAL);
68                 }
69
70         g_free(buf);
71         g_free(buf_casefold);
72         g_free(error_casefold);
73         g_free(warning_casefold);
74         return FALSE;
75 }
76
77 void log_domain_print_message(const gchar *domain, gchar *buf)
78 {
79         gchar *buf_nl;
80         regex_t regex;
81         gint ret_comp, ret_exec;
82
83         buf_nl = g_strconcat(buf, "\n", NULL);
84
85         if (regexp && command_line)
86                 {
87                         ret_comp = regcomp(&regex, regexp, 0);
88                         if (!ret_comp)
89                                 {
90                                 ret_exec = regexec(&regex, buf_nl, 0, NULL, 0);
91
92                                 if (!ret_exec)
93                                         {
94                                         print_term(FALSE, buf_nl);
95                                         if (strcmp(domain, DOMAIN_INFO) == 0)
96                                                 g_idle_add(log_normal_cb, buf_nl);
97                                         else
98                                                 g_idle_add(log_msg_cb, buf_nl);
99                                         }
100                                 regfree(&regex);
101                                 }
102                 }
103         else
104                 {
105                 print_term(FALSE, buf_nl);
106                 if (strcmp(domain, DOMAIN_INFO) == 0)
107                         g_idle_add(log_normal_cb, buf_nl);
108                 else
109                         g_idle_add(log_msg_cb, buf_nl);
110                 }
111         g_free(buf);
112 }
113
114 void log_domain_print_debug(const gchar *domain, const gchar *file_name, const gchar *function_name,
115                                                                         int line_number, const gchar *format, ...)
116 {
117         va_list ap;
118         gchar *message;
119         gchar *location;
120         gchar *buf;
121
122         va_start(ap, format);
123         message = g_strdup_vprintf(format, ap);
124         va_end(ap);
125
126         if (options && options->log_window.timer_data)
127                 {
128                 location = g_strdup_printf("%s:%s:%s:%d:", get_exec_time(), file_name,
129                                                                                                 function_name, line_number);
130                 }
131         else
132                 {
133                 location = g_strdup_printf("%s:%s:%d:", file_name, function_name, line_number);
134                 }
135
136         buf = g_strconcat(location, message, NULL);
137         log_domain_print_message(domain,buf);
138         g_free(location);
139         g_free(message);
140 }
141
142 void log_domain_printf(const gchar *domain, const gchar *format, ...)
143 {
144         va_list ap;
145         gchar *buf;
146
147         va_start(ap, format);
148         buf = g_strdup_vprintf(format, ap);
149         va_end(ap);
150
151         log_domain_print_message(domain, buf);
152 }
153
154 /*
155  * Debugging only functions
156  */
157
158 #ifdef DEBUG
159
160 static gint debug_level = DEBUG_LEVEL_MIN;
161
162
163 gint get_debug_level(void)
164 {
165         return debug_level;
166 }
167
168 void set_debug_level(gint new_level)
169 {
170         debug_level = CLAMP(new_level, DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX);
171 }
172
173 void debug_level_add(gint delta)
174 {
175         set_debug_level(debug_level + delta);
176 }
177
178 gint required_debug_level(gint level)
179 {
180         return (debug_level >= level);
181 }
182
183 static gint timeval_delta(struct timeval *result, struct timeval *x, struct timeval *y)
184 {
185         if (x->tv_usec < y->tv_usec)
186                 {
187                 gint nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
188                 y->tv_usec -= 1000000 * nsec;
189                 y->tv_sec += nsec;
190                 }
191
192         if (x->tv_usec - y->tv_usec > 1000000)
193                 {
194                 gint nsec = (x->tv_usec - y->tv_usec) / 1000000;
195                 y->tv_usec += 1000000 * nsec;
196                 y->tv_sec -= nsec;
197         }
198
199         result->tv_sec = x->tv_sec - y->tv_sec;
200         result->tv_usec = x->tv_usec - y->tv_usec;
201
202         return x->tv_sec < y->tv_sec;
203 }
204
205 const gchar *get_exec_time(void)
206 {
207         static gchar timestr[30];
208         static struct timeval start_tv = {0, 0};
209         static struct timeval previous = {0, 0};
210         static gint started = 0;
211
212         struct timeval tv = {0, 0};
213         static struct timeval delta = {0, 0};
214
215         gettimeofday(&tv, NULL);
216
217         if (start_tv.tv_sec == 0) start_tv = tv;
218
219         tv.tv_sec -= start_tv.tv_sec;
220         if (tv.tv_usec >= start_tv.tv_usec)
221                 tv.tv_usec -= start_tv.tv_usec;
222         else
223                 {
224                 tv.tv_usec += 1000000 - start_tv.tv_usec;
225                 tv.tv_sec -= 1;
226                 }
227
228         if (started) timeval_delta(&delta, &tv, &previous);
229
230         previous = tv;
231         started = 1;
232
233         g_snprintf(timestr, sizeof(timestr), "%5d.%06d (+%05d.%06d)", (gint)tv.tv_sec, (gint)tv.tv_usec, (gint)delta.tv_sec, (gint)delta.tv_usec);
234
235         return timestr;
236 }
237
238 void init_exec_time(void)
239 {
240         get_exec_time();
241 }
242
243 void set_regexp(gchar *cmd_regexp)
244 {
245         regexp = g_strdup(cmd_regexp);
246 }
247
248 gchar *get_regexp(void)
249 {
250         return g_strdup(regexp);
251 }
252
253 #endif /* DEBUG */
254 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */