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.
25 #include "logwindow.h"
27 #include "ui-fileops.h"
29 #ifdef HAVE_EXECINFO_H
38 static gchar *regexp = nullptr;
40 static gboolean log_msg_cb(gpointer data)
42 auto buf = static_cast<gchar *>(data);
43 log_window_append(buf, LOG_MSG);
49 * @brief Appends a user information message to the log window queue
50 * @param data The message
53 * If the first word of the message is either "error" or "warning"
54 * (case insensitive) the message is color-coded appropriately
56 static gboolean log_normal_cb(gpointer data)
58 auto buf = static_cast<gchar *>(data);
59 gchar *buf_casefold = g_utf8_casefold(buf, -1);
60 gchar *error_casefold = g_utf8_casefold(_("error"), -1);
61 gchar *warning_casefold = g_utf8_casefold(_("warning"), -1);
63 if (buf_casefold == g_strstr_len(buf_casefold, -1, error_casefold))
65 log_window_append(buf, LOG_ERROR);
67 else if (buf_casefold == g_strstr_len(buf_casefold, -1, warning_casefold))
69 log_window_append(buf, LOG_WARN);
73 log_window_append(buf, LOG_NORMAL);
78 g_free(error_casefold);
79 g_free(warning_casefold);
83 void log_domain_print_message(const gchar *domain, gchar *buf)
90 buf_nl = g_strconcat(buf, "\n", NULL);
92 if (regexp && command_line)
94 ret_comp = regcomp(®ex, regexp, 0);
97 ret_exec = regexec(®ex, buf_nl, 0, nullptr, 0);
101 print_term(FALSE, buf_nl);
102 if (strcmp(domain, DOMAIN_INFO) == 0)
103 g_idle_add(log_normal_cb, buf_nl);
105 g_idle_add(log_msg_cb, buf_nl);
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);
121 void log_domain_print_debug(const gchar *domain, const gchar *file_name, int line_number, const gchar *function_name, const gchar *format, ...)
128 va_start(ap, format);
129 message = g_strdup_vprintf(format, ap);
132 if (options && options->log_window.timer_data)
134 location = g_strdup_printf("%s:%s:%d:%s:", get_exec_time(), file_name, line_number, function_name);
138 location = g_strdup_printf("%s:%d:%s:", file_name, line_number, function_name);
141 buf = g_strconcat(location, message, NULL);
142 log_domain_print_message(domain,buf);
147 void log_domain_printf(const gchar *domain, const gchar *format, ...)
152 va_start(ap, format);
153 buf = g_strdup_vprintf(format, ap);
156 log_domain_print_message(domain, buf);
160 * Debugging only functions
165 static gint debug_level = DEBUG_LEVEL_MIN;
168 gint get_debug_level()
173 void set_debug_level(gint new_level)
175 debug_level = CLAMP(new_level, DEBUG_LEVEL_MIN, DEBUG_LEVEL_MAX);
178 void debug_level_add(gint delta)
180 set_debug_level(debug_level + delta);
183 gint required_debug_level(gint level)
185 return (debug_level >= level);
188 static gint timeval_delta(struct timeval *result, struct timeval *x, struct timeval *y)
190 if (x->tv_usec < y->tv_usec)
192 gint nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
193 y->tv_usec -= 1000000 * nsec;
197 if (x->tv_usec - y->tv_usec > 1000000)
199 gint nsec = (x->tv_usec - y->tv_usec) / 1000000;
200 y->tv_usec += 1000000 * nsec;
204 result->tv_sec = x->tv_sec - y->tv_sec;
205 result->tv_usec = x->tv_usec - y->tv_usec;
207 return x->tv_sec < y->tv_sec;
210 const gchar *get_exec_time()
212 static gchar timestr[30];
213 static struct timeval start_tv = {0, 0};
214 static struct timeval previous = {0, 0};
215 static gint started = 0;
217 struct timeval tv = {0, 0};
218 static struct timeval delta = {0, 0};
220 gettimeofday(&tv, nullptr);
222 if (start_tv.tv_sec == 0) start_tv = tv;
224 tv.tv_sec -= start_tv.tv_sec;
225 if (tv.tv_usec >= start_tv.tv_usec)
226 tv.tv_usec -= start_tv.tv_usec;
229 tv.tv_usec += 1000000 - start_tv.tv_usec;
233 if (started) timeval_delta(&delta, &tv, &previous);
238 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));
243 void init_exec_time()
248 void set_regexp(const gchar *cmd_regexp)
250 regexp = g_strdup(cmd_regexp);
255 return g_strdup(regexp);
258 #ifdef HAVE_EXECINFO_H
260 * @brief Backtrace of geeqie files
265 * Requires command line program addr2line \n
266 * Prints the contents of the backtrace buffer for Geeqie files. \n
267 * Format printed is: \n
268 * <full path to source file>:<line number>
270 * The log window F1 command and Edit/Preferences/Behavior/Log Window F1
271 * Command may be used to open an editor at a backtrace location.
273 void log_print_backtrace(const gchar *file, gint line, const gchar *function)
278 gchar *address_offset;
281 gchar *function_name = nullptr;
288 if (runcmd(reinterpret_cast<const gchar *>("which addr2line >/dev/null 2>&1")) == 0)
290 exe_path = g_path_get_dirname(gq_executable_path);
291 bt_size = backtrace(bt, 1024);
292 bt_syms = backtrace_symbols(bt, bt_size);
294 log_printf("Backtrace start");
295 log_printf("%s/../%s:%d %s\n", exe_path, file, line, function);
297 /* Last item is always "??:?", so ignore it */
298 for (i = 1; i < bt_size - 1; i++)
300 if (strstr(bt_syms[i], GQ_APPNAME_LC))
302 paren_start = g_strstr_len(bt_syms[i], -1, "(");
303 paren_end = g_strstr_len(bt_syms[i], -1, ")");
304 address_offset = g_strndup(paren_start + 1, paren_end - paren_start - 1);
306 cmd_line = g_strconcat("addr2line -p -f -C -e ", gq_executable_path, " ", address_offset, NULL);
308 fp = popen(cmd_line, "r");
311 log_printf("Failed to run command: %s", cmd_line);
315 while (fgets(path, sizeof(path), fp) != nullptr)
317 /* Remove redundant newline */
318 path[strlen(path) - 1] = '\0';
320 if (g_strstr_len(path, strlen(path), "(") != nullptr)
322 function_name = g_strndup(path, g_strstr_len(path, strlen(path), "(") - path);
326 function_name = g_strdup("");
328 log_printf("%s %s", g_strstr_len(path, -1, "at ") + 3, function_name);
330 g_free(function_name);
336 g_free(address_offset);
340 log_printf("Backtrace end");
347 void log_print_backtrace(const gchar *, gint, const gchar *)
353 * @brief Print ref. count and image name
358 * Print image ref. count and full path name of all images in
359 * the file_data_pool.
361 void log_print_file_data_dump(const gchar *file, const gchar *function, gint line)
365 exe_path = g_path_get_dirname(gq_executable_path);
367 log_printf("FileData dump start");
368 log_printf("%s/../%s:%d %s\n", exe_path, file, line, function);
372 log_printf("FileData dump end");
378 /* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */