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.
34 # include <execinfo.h>
39 #include "logwindow.h"
40 #include "main-defines.h"
44 #include "ui-fileops.h"
49 static gchar *regexp = nullptr;
51 static gboolean log_msg_cb(gpointer data)
53 auto buf = static_cast<gchar *>(data);
54 log_window_append(buf, LOG_MSG);
60 * @brief Appends a user information message to the log window queue
61 * @param data The message
64 * If the first word of the message is either "error" or "warning"
65 * (case insensitive) the message is color-coded appropriately
67 static gboolean log_normal_cb(gpointer data)
69 auto buf = static_cast<gchar *>(data);
70 gchar *buf_casefold = g_utf8_casefold(buf, -1);
71 gchar *error_casefold = g_utf8_casefold(_("error"), -1);
72 gchar *warning_casefold = g_utf8_casefold(_("warning"), -1);
74 if (buf_casefold == g_strstr_len(buf_casefold, -1, error_casefold))
76 log_window_append(buf, LOG_ERROR);
78 else if (buf_casefold == g_strstr_len(buf_casefold, -1, warning_casefold))
80 log_window_append(buf, LOG_WARN);
84 log_window_append(buf, LOG_NORMAL);
89 g_free(error_casefold);
90 g_free(warning_casefold);
94 void log_domain_print_message(const gchar *domain, gchar *buf)
101 buf_nl = g_strconcat(buf, "\n", NULL);
103 if (regexp && command_line)
105 ret_comp = regcomp(®ex, regexp, 0);
108 ret_exec = regexec(®ex, buf_nl, 0, nullptr, 0);
112 print_term(FALSE, buf_nl);
113 if (strcmp(domain, DOMAIN_INFO) == 0)
114 g_idle_add(log_normal_cb, buf_nl);
116 g_idle_add(log_msg_cb, buf_nl);
123 print_term(FALSE, buf_nl);
124 if (strcmp(domain, DOMAIN_INFO) == 0)
125 g_idle_add(log_normal_cb, buf_nl);
127 g_idle_add(log_msg_cb, buf_nl);
132 void log_domain_print_debug(const gchar *domain, const gchar *file_name, int line_number, const gchar *function_name, const gchar *format, ...)
139 va_start(ap, format);
140 message = g_strdup_vprintf(format, ap);
143 if (options && options->log_window.timer_data)
145 location = g_strdup_printf("%s:%s:%d:%s:", get_exec_time(), file_name, line_number, function_name);
149 location = g_strdup_printf("%s:%d:%s:", file_name, line_number, function_name);
152 buf = g_strconcat(location, message, NULL);
153 log_domain_print_message(domain,buf);
158 void log_domain_printf(const gchar *domain, const gchar *format, ...)
163 va_start(ap, format);
164 buf = g_strdup_vprintf(format, ap);
167 log_domain_print_message(domain, buf);
171 * Debugging only functions
176 static gint debug_level = DEBUG_LEVEL_MIN;
179 gint get_debug_level()
184 void set_debug_level(gint new_level)
186 debug_level = CLAMP(new_level, DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX);
189 void debug_level_add(gint delta)
191 set_debug_level(debug_level + delta);
194 gint required_debug_level(gint level)
196 return (debug_level >= level);
199 static gint timeval_delta(struct timeval *result, struct timeval *x, struct timeval *y)
201 if (x->tv_usec < y->tv_usec)
203 gint nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
204 y->tv_usec -= 1000000 * nsec;
208 if (x->tv_usec - y->tv_usec > 1000000)
210 gint nsec = (x->tv_usec - y->tv_usec) / 1000000;
211 y->tv_usec += 1000000 * nsec;
215 result->tv_sec = x->tv_sec - y->tv_sec;
216 result->tv_usec = x->tv_usec - y->tv_usec;
218 return x->tv_sec < y->tv_sec;
221 const gchar *get_exec_time()
223 static gchar timestr[30];
224 static struct timeval start_tv = {0, 0};
225 static struct timeval previous = {0, 0};
226 static gint started = 0;
228 struct timeval tv = {0, 0};
229 static struct timeval delta = {0, 0};
231 gettimeofday(&tv, nullptr);
233 if (start_tv.tv_sec == 0) start_tv = tv;
235 tv.tv_sec -= start_tv.tv_sec;
236 if (tv.tv_usec >= start_tv.tv_usec)
237 tv.tv_usec -= start_tv.tv_usec;
240 tv.tv_usec += 1000000 - start_tv.tv_usec;
244 if (started) timeval_delta(&delta, &tv, &previous);
249 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));
254 void init_exec_time()
259 void set_regexp(const gchar *cmd_regexp)
261 regexp = g_strdup(cmd_regexp);
266 return g_strdup(regexp);
271 * @brief Backtrace of geeqie files
276 * Requires command line program addr2line \n
277 * Prints the contents of the backtrace buffer for Geeqie files. \n
278 * Format printed is: \n
279 * <full path to source file>:<line number>
281 * The log window F1 command and Edit/Preferences/Behavior/Log Window F1
282 * Command may be used to open an editor at a backtrace location.
284 void log_print_backtrace(const gchar *file, gint line, const gchar *function)
289 gchar *address_offset;
292 gchar *function_name = nullptr;
299 if (runcmd(reinterpret_cast<const gchar *>("which addr2line >/dev/null 2>&1")) == 0)
301 exe_path = g_path_get_dirname(gq_executable_path);
302 bt_size = backtrace(bt, 1024);
303 bt_syms = backtrace_symbols(bt, bt_size);
305 log_printf("Backtrace start");
306 log_printf("%s/../%s:%d %s\n", exe_path, file, line, function);
308 /* Last item is always "??:?", so ignore it */
309 for (i = 1; i < bt_size - 1; i++)
311 if (strstr(bt_syms[i], GQ_APPNAME_LC))
313 paren_start = g_strstr_len(bt_syms[i], -1, "(");
314 paren_end = g_strstr_len(bt_syms[i], -1, ")");
315 address_offset = g_strndup(paren_start + 1, paren_end - paren_start - 1);
317 cmd_line = g_strconcat("addr2line -p -f -C -e ", gq_executable_path, " ", address_offset, NULL);
319 fp = popen(cmd_line, "r");
322 log_printf("Failed to run command: %s", cmd_line);
326 while (fgets(path, sizeof(path), fp) != nullptr)
328 /* Remove redundant newline */
329 path[strlen(path) - 1] = '\0';
331 if (g_strstr_len(path, strlen(path), "(") != nullptr)
333 function_name = g_strndup(path, g_strstr_len(path, strlen(path), "(") - path);
337 function_name = g_strdup("");
339 log_printf("%s %s", g_strstr_len(path, -1, "at ") + 3, function_name);
341 g_free(function_name);
347 g_free(address_offset);
351 log_printf("Backtrace end");
358 void log_print_backtrace(const gchar *, gint, const gchar *)
364 * @brief Print ref. count and image name
369 * Print image ref. count and full path name of all images in
370 * the file_data_pool.
372 void log_print_file_data_dump(const gchar *file, const gchar *function, gint line)
376 exe_path = g_path_get_dirname(gq_executable_path);
378 log_printf("FileData dump start");
379 log_printf("%s/../%s:%d %s\n", exe_path, file, line, function);
383 log_printf("FileData dump end");
389 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */