2 * Copyright (C) 2008 - 2016 The Geeqie Team
4 * Authors: Vladimir Nadvornik, Laurent Monin
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.
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.
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.
27 #include "logwindow.h"
29 #include "main-defines.h"
32 #include "ui-fileops.h"
34 #ifdef HAVE_EXECINFO_H
43 static gchar *regexp = nullptr;
45 static gboolean log_msg_cb(gpointer data)
47 auto buf = static_cast<gchar *>(data);
48 log_window_append(buf, LOG_MSG);
54 * @brief Appends a user information message to the log window queue
55 * @param data The message
58 * If the first word of the message is either "error" or "warning"
59 * (case insensitive) the message is color-coded appropriately
61 static gboolean log_normal_cb(gpointer data)
63 auto buf = static_cast<gchar *>(data);
64 gchar *buf_casefold = g_utf8_casefold(buf, -1);
65 gchar *error_casefold = g_utf8_casefold(_("error"), -1);
66 gchar *warning_casefold = g_utf8_casefold(_("warning"), -1);
68 if (buf_casefold == g_strstr_len(buf_casefold, -1, error_casefold))
70 log_window_append(buf, LOG_ERROR);
72 else if (buf_casefold == g_strstr_len(buf_casefold, -1, warning_casefold))
74 log_window_append(buf, LOG_WARN);
78 log_window_append(buf, LOG_NORMAL);
83 g_free(error_casefold);
84 g_free(warning_casefold);
88 void log_domain_print_message(const gchar *domain, gchar *buf)
95 buf_nl = g_strconcat(buf, "\n", NULL);
97 if (regexp && command_line)
99 ret_comp = regcomp(®ex, regexp, 0);
102 ret_exec = regexec(®ex, buf_nl, 0, nullptr, 0);
106 print_term(FALSE, buf_nl);
107 if (strcmp(domain, DOMAIN_INFO) == 0)
108 g_idle_add(log_normal_cb, buf_nl);
110 g_idle_add(log_msg_cb, buf_nl);
117 print_term(FALSE, buf_nl);
118 if (strcmp(domain, DOMAIN_INFO) == 0)
119 g_idle_add(log_normal_cb, buf_nl);
121 g_idle_add(log_msg_cb, buf_nl);
126 void log_domain_print_debug(const gchar *domain, const gchar *file_name, int line_number, const gchar *function_name, const gchar *format, ...)
133 va_start(ap, format);
134 message = g_strdup_vprintf(format, ap);
137 if (options && options->log_window.timer_data)
139 location = g_strdup_printf("%s:%s:%d:%s:", get_exec_time(), file_name, line_number, function_name);
143 location = g_strdup_printf("%s:%d:%s:", file_name, line_number, function_name);
146 buf = g_strconcat(location, message, NULL);
147 log_domain_print_message(domain,buf);
152 void log_domain_printf(const gchar *domain, const gchar *format, ...)
157 va_start(ap, format);
158 buf = g_strdup_vprintf(format, ap);
161 log_domain_print_message(domain, buf);
165 * Debugging only functions
170 static gint debug_level = DEBUG_LEVEL_MIN;
173 gint get_debug_level()
178 void set_debug_level(gint new_level)
180 debug_level = CLAMP(new_level, DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX);
183 void debug_level_add(gint delta)
185 set_debug_level(debug_level + delta);
188 gint required_debug_level(gint level)
190 return (debug_level >= level);
193 static gint timeval_delta(struct timeval *result, struct timeval *x, struct timeval *y)
195 if (x->tv_usec < y->tv_usec)
197 gint nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
198 y->tv_usec -= 1000000 * nsec;
202 if (x->tv_usec - y->tv_usec > 1000000)
204 gint nsec = (x->tv_usec - y->tv_usec) / 1000000;
205 y->tv_usec += 1000000 * nsec;
209 result->tv_sec = x->tv_sec - y->tv_sec;
210 result->tv_usec = x->tv_usec - y->tv_usec;
212 return x->tv_sec < y->tv_sec;
215 const gchar *get_exec_time()
217 static gchar timestr[30];
218 static struct timeval start_tv = {0, 0};
219 static struct timeval previous = {0, 0};
220 static gint started = 0;
222 struct timeval tv = {0, 0};
223 static struct timeval delta = {0, 0};
225 gettimeofday(&tv, nullptr);
227 if (start_tv.tv_sec == 0) start_tv = tv;
229 tv.tv_sec -= start_tv.tv_sec;
230 if (tv.tv_usec >= start_tv.tv_usec)
231 tv.tv_usec -= start_tv.tv_usec;
234 tv.tv_usec += 1000000 - start_tv.tv_usec;
238 if (started) timeval_delta(&delta, &tv, &previous);
243 g_snprintf(timestr, sizeof(timestr), "%5d.%06d (+%05d.%06d)", static_cast<gint>(tv.tv_sec), static_cast<gint>(tv.tv_usec), static_cast<gint>(delta.tv_sec), static_cast<gint>(delta.tv_usec));
248 void init_exec_time()
253 void set_regexp(const gchar *cmd_regexp)
255 regexp = g_strdup(cmd_regexp);
260 return g_strdup(regexp);
263 #ifdef HAVE_EXECINFO_H
265 * @brief Backtrace of geeqie files
270 * Requires command line program addr2line \n
271 * Prints the contents of the backtrace buffer for Geeqie files. \n
272 * Format printed is: \n
273 * <full path to source file>:<line number>
275 * The log window F1 command and Edit/Preferences/Behavior/Log Window F1
276 * Command may be used to open an editor at a backtrace location.
278 void log_print_backtrace(const gchar *file, gint line, const gchar *function)
283 gchar *address_offset;
286 gchar *function_name = nullptr;
293 if (runcmd(reinterpret_cast<const gchar *>("which addr2line >/dev/null 2>&1")) == 0)
295 exe_path = g_path_get_dirname(gq_executable_path);
296 bt_size = backtrace(bt, 1024);
297 bt_syms = backtrace_symbols(bt, bt_size);
299 log_printf("Backtrace start");
300 log_printf("%s/../%s:%d %s\n", exe_path, file, line, function);
302 /* Last item is always "??:?", so ignore it */
303 for (i = 1; i < bt_size - 1; i++)
305 if (strstr(bt_syms[i], GQ_APPNAME_LC))
307 paren_start = g_strstr_len(bt_syms[i], -1, "(");
308 paren_end = g_strstr_len(bt_syms[i], -1, ")");
309 address_offset = g_strndup(paren_start + 1, paren_end - paren_start - 1);
311 cmd_line = g_strconcat("addr2line -p -f -C -e ", gq_executable_path, " ", address_offset, NULL);
313 fp = popen(cmd_line, "r");
316 log_printf("Failed to run command: %s", cmd_line);
320 while (fgets(path, sizeof(path), fp) != nullptr)
322 /* Remove redundant newline */
323 path[strlen(path) - 1] = '\0';
325 if (g_strstr_len(path, strlen(path), "(") != nullptr)
327 function_name = g_strndup(path, g_strstr_len(path, strlen(path), "(") - path);
331 function_name = g_strdup("");
333 log_printf("%s %s", g_strstr_len(path, -1, "at ") + 3, function_name);
335 g_free(function_name);
341 g_free(address_offset);
345 log_printf("Backtrace end");
352 void log_print_backtrace(const gchar *, gint, const gchar *)
358 * @brief Print ref. count and image name
363 * Print image ref. count and full path name of all images in
364 * the file_data_pool.
366 void log_print_file_data_dump(const gchar *file, const gchar *function, gint line)
370 exe_path = g_path_get_dirname(gq_executable_path);
372 log_printf("FileData dump start");
373 log_printf("%s/../%s:%d %s\n", exe_path, file, line, function);
377 log_printf("FileData dump end");
383 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */