Simplify vflist_get_formatted()
[geeqie.git] / src / debug.c
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 <glib/gprintf.h>
28 #include <regex.h>
29
30 /*
31  * Logging functions
32  */
33 static gchar *regexp = NULL;
34
35 static gboolean log_msg_cb(gpointer data)
36 {
37         gchar *buf = data;
38         log_window_append(buf, LOG_MSG);
39         g_free(buf);
40         return FALSE;
41 }
42
43 /**
44  * @brief Appends a user information message to the log window queue
45  * @param data The message
46  * @returns FALSE
47  * 
48  * If the first word of the message is either "error" or "warning"
49  * (case insensitive) the message is color-coded appropriately
50  */
51 static gboolean log_normal_cb(gpointer data)
52 {
53         gchar *buf = data;
54         gchar *buf_casefold = g_utf8_casefold(buf, -1);
55         gchar *error_casefold = g_utf8_casefold(_("error"), -1);
56         gchar *warning_casefold = g_utf8_casefold(_("warning"), -1);
57
58         if (buf_casefold == g_strstr_len(buf_casefold, -1, error_casefold))
59                 {
60                 log_window_append(buf, LOG_ERROR);
61                 }
62         else if (buf_casefold == g_strstr_len(buf_casefold, -1, warning_casefold))
63                 {
64                 log_window_append(buf, LOG_WARN);
65                 }
66         else
67                 {
68                 log_window_append(buf, LOG_NORMAL);
69                 }
70
71         g_free(buf);
72         g_free(buf_casefold);
73         g_free(error_casefold);
74         g_free(warning_casefold);
75         return FALSE;
76 }
77
78 void log_domain_print_message(const gchar *domain, gchar *buf)
79 {
80         gchar *buf_nl;
81         regex_t regex;
82         gint ret_comp, ret_exec;
83
84         buf_nl = g_strconcat(buf, "\n", NULL);
85
86         if (regexp && command_line)
87                 {
88                         ret_comp = regcomp(&regex, regexp, 0);
89                         if (!ret_comp)
90                                 {
91                                 ret_exec = regexec(&regex, buf_nl, 0, NULL, 0);
92
93                                 if (!ret_exec)
94                                         {
95                                         print_term(FALSE, buf_nl);
96                                         if (strcmp(domain, DOMAIN_INFO) == 0)
97                                                 g_idle_add(log_normal_cb, buf_nl);
98                                         else
99                                                 g_idle_add(log_msg_cb, buf_nl);
100                                         }
101                                 regfree(&regex);
102                                 }
103                 }
104         else
105                 {
106                 print_term(FALSE, buf_nl);
107                 if (strcmp(domain, DOMAIN_INFO) == 0)
108                         g_idle_add(log_normal_cb, buf_nl);
109                 else
110                         g_idle_add(log_msg_cb, buf_nl);
111                 }
112         g_free(buf);
113 }
114
115 void log_domain_print_debug(const gchar *domain, const gchar *file_name, const gchar *function_name,
116                                                                         int line_number, const gchar *format, ...)
117 {
118         va_list ap;
119         gchar *message;
120         gchar *location;
121         gchar *buf;
122
123         va_start(ap, format);
124         message = g_strdup_vprintf(format, ap);
125         va_end(ap);
126
127         if (options && options->log_window.timer_data)
128                 {
129                 location = g_strdup_printf("%s:%s:%s:%d:", get_exec_time(), file_name,
130                                                                                                 function_name, line_number);
131                 }
132         else
133                 {
134                 location = g_strdup_printf("%s:%s:%d:", file_name, function_name, line_number);
135                 }
136
137         buf = g_strconcat(location, message, NULL);
138         log_domain_print_message(domain,buf);
139         g_free(location);
140         g_free(message);
141 }
142
143 void log_domain_printf(const gchar *domain, const gchar *format, ...)
144 {
145         va_list ap;
146         gchar *buf;
147
148         va_start(ap, format);
149         buf = g_strdup_vprintf(format, ap);
150         va_end(ap);
151
152         log_domain_print_message(domain, buf);
153 }
154
155 /*
156  * Debugging only functions
157  */
158
159 #ifdef DEBUG
160
161 static gint debug_level = DEBUG_LEVEL_MIN;
162
163
164 gint get_debug_level(void)
165 {
166         return debug_level;
167 }
168
169 void set_debug_level(gint new_level)
170 {
171         debug_level = CLAMP(new_level, DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX);
172 }
173
174 void debug_level_add(gint delta)
175 {
176         set_debug_level(debug_level + delta);
177 }
178
179 gint required_debug_level(gint level)
180 {
181         return (debug_level >= level);
182 }
183
184 static gint timeval_delta(struct timeval *result, struct timeval *x, struct timeval *y)
185 {
186         if (x->tv_usec < y->tv_usec)
187                 {
188                 gint nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
189                 y->tv_usec -= 1000000 * nsec;
190                 y->tv_sec += nsec;
191                 }
192
193         if (x->tv_usec - y->tv_usec > 1000000)
194                 {
195                 gint nsec = (x->tv_usec - y->tv_usec) / 1000000;
196                 y->tv_usec += 1000000 * nsec;
197                 y->tv_sec -= nsec;
198         }
199
200         result->tv_sec = x->tv_sec - y->tv_sec;
201         result->tv_usec = x->tv_usec - y->tv_usec;
202
203         return x->tv_sec < y->tv_sec;
204 }
205
206 const gchar *get_exec_time(void)
207 {
208         static gchar timestr[30];
209         static struct timeval start_tv = {0, 0};
210         static struct timeval previous = {0, 0};
211         static gint started = 0;
212
213         struct timeval tv = {0, 0};
214         static struct timeval delta = {0, 0};
215
216         gettimeofday(&tv, NULL);
217
218         if (start_tv.tv_sec == 0) start_tv = tv;
219
220         tv.tv_sec -= start_tv.tv_sec;
221         if (tv.tv_usec >= start_tv.tv_usec)
222                 tv.tv_usec -= start_tv.tv_usec;
223         else
224                 {
225                 tv.tv_usec += 1000000 - start_tv.tv_usec;
226                 tv.tv_sec -= 1;
227                 }
228
229         if (started) timeval_delta(&delta, &tv, &previous);
230
231         previous = tv;
232         started = 1;
233
234         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);
235
236         return timestr;
237 }
238
239 void init_exec_time(void)
240 {
241         get_exec_time();
242 }
243
244 void set_regexp(gchar *cmd_regexp)
245 {
246         regexp = g_strdup(cmd_regexp);
247 }
248
249 gchar *get_regexp(void)
250 {
251         return g_strdup(regexp);
252 }
253
254 #endif /* DEBUG */
255 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */