/* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * Copyright (C) 2007-2011 Kouhei Sutou * * This library is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public License * along with this program. If not, see . * */ #ifdef HAVE_CONFIG_H # include #endif /* HAVE_CONFIG_H */ #include #include #ifdef HAVE_UNISTD_H # include #endif #include #include #ifdef G_OS_WIN32 # include # include # define close _close #endif #include #include "cut-utils.h" #include "cut-sub-process.h" #include "cut-sub-process-group.h" #include "cut-readable-differ.h" #include "cut-main.h" #include "cut-backtrace-entry.h" #include "../gcutter/gcut-public.h" #include "../gcutter/gcut-error.h" #include "../gcutter/gcut-assertions-helper.h" #ifndef CUT_DISABLE_SOCKET_SUPPORT # ifdef CUT_HAVE_WINSOCK2_H # include # include # else # include # include # include # include # ifdef HAVE_SYS_UN_H # include # endif # endif #endif gchar * cut_utils_create_regex_pattern (const gchar *string) { gchar *pattern; if (!string) { pattern = g_strdup(".*"); } else if (strlen(string) > 1 && g_str_has_prefix(string, "/") && g_str_has_suffix(string, "/")) { pattern = g_strndup(string + 1, strlen(string) - 2); } else { gchar *escaped_string; escaped_string = g_regex_escape_string(string, -1); pattern = g_strdup_printf("^%s$", escaped_string); g_free(escaped_string); } return pattern; } GList * cut_utils_filter_to_regexs (const gchar **filter) { GList *regexs = NULL; for (; *filter; filter++) { GRegex *regex; gchar *pattern; GError *error = NULL; if (*filter[0] == '\0') continue; pattern = cut_utils_create_regex_pattern(*filter); regex = g_regex_new(pattern, 0, 0, &error); if (regex) { regexs = g_list_prepend(regexs, regex); } else { cut_utils_report_error(error); } g_free(pattern); } return regexs; } gboolean cut_utils_filter_match (GList *regexs, const gchar *name) { GList *node; for (node = regexs; node; node = g_list_next(node)) { GRegex *regex = node->data; if (g_regex_match(regex, name, 0, NULL)) return TRUE; } return FALSE; } gchar * cut_utils_inspect_memory (const void *memory, size_t size) { const guchar *binary = memory; GString *buffer; size_t i, n_printable_characters; size_t max_size = 1024; if (memory == NULL || size == 0) return g_strdup("(null)"); buffer = g_string_sized_new(size * strlen("0xXX") + (size - 1) * strlen(" ") + strlen(": ") + size); max_size = MIN(size, max_size); n_printable_characters = 0; for (i = 0; i < max_size; i++) { g_string_append_printf(buffer, "0x%02x ", binary[i]); if (g_ascii_isprint(binary[i])) n_printable_characters++; } if (size > max_size) g_string_append(buffer, "... "); if (n_printable_characters >= max_size * 0.3) { g_string_overwrite(buffer, buffer->len - 1, ": "); for (i = 0; i < max_size; i++) { if (g_ascii_isprint(binary[i])) { g_string_append_c(buffer, binary[i]); } else { g_string_append_c(buffer, '.'); } } if (size > max_size) g_string_append(buffer, "..."); } else { g_string_truncate(buffer, buffer->len - 1); } return g_string_free(buffer, FALSE); } gboolean cut_utils_equal_string (const gchar *string1, const gchar *string2) { if (string1 == string2) return TRUE; if (string1 == NULL || string2 == NULL) return FALSE; return g_str_equal(string1, string2); } gboolean cut_utils_equal_substring (const gchar *string1, const gchar *string2, size_t length) { if (string1 == string2) return TRUE; if (string1 == NULL || string2 == NULL) return FALSE; return strncmp(string1, string2, length) == 0; } gboolean cut_utils_equal_double (gdouble double1, gdouble double2, gdouble error) { return fabs(double1 - double2) <= error; } gboolean cut_utils_equal_string_array (gchar **strings1, gchar **strings2) { gint i, length; if (!strings1 && !strings2) return TRUE; if (!strings1 || !strings2) return FALSE; length = g_strv_length(strings1); if (length != g_strv_length(strings2)) return FALSE; for (i = 0; i < length; i++) { if (strcmp(strings1[i], strings2[i])) return FALSE; } return TRUE; } static void cut_utils_inspect_string_to_gstring (GString *inspected, const gchar *string) { if (!string) { g_string_append(inspected, "(null)"); return; } g_string_append_c(inspected, '"'); for (; string[0]; string++) { switch (string[0]) { case '"': g_string_append(inspected, "\\\""); break; case '\\': g_string_append(inspected, "\\\\"); break; default: g_string_append_c(inspected, string[0]); break; } } g_string_append_c(inspected, '"'); } gchar * cut_utils_inspect_string_array (gchar **strings) { GString *inspected; gchar **string, **next_string; if (!strings) return g_strdup("(null)"); inspected = g_string_new("["); string = strings; while (*string) { cut_utils_inspect_string_to_gstring(inspected, *string); next_string = string + 1; if (*next_string) g_string_append(inspected, ", "); string = next_string; } g_string_append(inspected, "]"); return g_string_free(inspected, FALSE); } gchar * cut_utils_inspect_string (const gchar *string) { GString *inspected; inspected = g_string_new(NULL); cut_utils_inspect_string_to_gstring(inspected, string); return g_string_free(inspected, FALSE); } #ifndef CUT_DISABLE_SOCKET_SUPPORT gboolean cut_utils_equal_sockaddr (const struct sockaddr *address1, const struct sockaddr *address2) { if (address1 == address2) return TRUE; if (!address1 || !address2) return FALSE; if (address1->sa_family != address2->sa_family) return FALSE; switch (address1->sa_family) { #ifdef HAVE_SYS_UN_H case AF_UNIX: { struct sockaddr_un *address_unix1 = (struct sockaddr_un *)address1; struct sockaddr_un *address_unix2 = (struct sockaddr_un *)address2; return cut_utils_equal_string(address_unix1->sun_path, address_unix2->sun_path); break; } #endif case AF_INET: { struct sockaddr_in *address_inet1 = (struct sockaddr_in *)address1; struct sockaddr_in *address_inet2 = (struct sockaddr_in *)address2; if (address_inet1->sin_addr.s_addr != address_inet2->sin_addr.s_addr) return FALSE; if (address_inet1->sin_port != address_inet2->sin_port) return FALSE; return TRUE; break; } case AF_INET6: { struct sockaddr_in6 *address_inet6_1 = (struct sockaddr_in6 *)address1; struct sockaddr_in6 *address_inet6_2 = (struct sockaddr_in6 *)address2; if (memcmp(address_inet6_1->sin6_addr.s6_addr, address_inet6_2->sin6_addr.s6_addr, sizeof(address_inet6_1->sin6_addr.s6_addr)) != 0) return FALSE; if (address_inet6_1->sin6_port != address_inet6_2->sin6_port) return FALSE; return TRUE; break; } case AF_UNSPEC: return TRUE; break; default: return FALSE; break; } return FALSE; } #ifdef G_OS_WIN32 # if !defined(NTDDI_VERSION) || (NTDDI_VERSION < NTDDI_LONGHORN) static const char * inet_ntop (int address_family, const void *source, char *destination, socklen_t destination_length) { DWORD socket_address_length; DWORD winsock_destination_length = destination_length; switch (address_family) { case AF_INET: socket_address_length = sizeof(struct sockaddr_in); break; case AF_INET6: socket_address_length = sizeof(struct sockaddr_in6); break; default: return NULL; break; } if (WSAAddressToString((LPSOCKADDR)source, socket_address_length, NULL, destination, &winsock_destination_length)) { return NULL; } else { return destination; } } # endif #endif gchar * cut_utils_inspect_sockaddr (const struct sockaddr *address) { gchar *spec = NULL; if (!address) return g_strdup("(null)"); switch (address->sa_family) { #ifdef HAVE_SYS_UN_H case AF_UNIX: { struct sockaddr_un *address_unix = (struct sockaddr_un *)address; spec = g_strdup_printf("unix:%s", address_unix->sun_path); break; } #endif case AF_INET: { struct sockaddr_in *address_inet = (struct sockaddr_in *)address; gchar ip_address_string[INET_ADDRSTRLEN]; if (inet_ntop(AF_INET, &address_inet->sin_addr, (gchar *)ip_address_string, INET_ADDRSTRLEN)) { spec = g_strdup_printf("inet:%s:%d", ip_address_string, g_ntohs(address_inet->sin_port)); } break; } case AF_INET6: { struct sockaddr_in6 *address_inet6 = (struct sockaddr_in6 *)address; gchar ip_address_string[INET6_ADDRSTRLEN]; if (inet_ntop(AF_INET6, &address_inet6->sin6_addr, (gchar *)ip_address_string, INET6_ADDRSTRLEN)) { spec = g_strdup_printf("inet6:[%s]:%d", ip_address_string, g_ntohs(address_inet6->sin6_port)); } break; } case AF_UNSPEC: spec = g_strdup("unknown"); break; default: spec = g_strdup_printf("unexpected:%d", address->sa_family); break; } return spec; } #endif gboolean cut_utils_path_exist (const gchar *path) { return g_file_test(path, G_FILE_TEST_EXISTS); } gboolean cut_utils_regex_match (const gchar *pattern, const gchar *string) { return g_regex_match_simple(pattern, string, G_REGEX_MULTILINE, 0); } gchar * cut_utils_regex_replace (const gchar *pattern, const gchar *string, const gchar *replacement, GError **error) { GRegex *regex; gchar *replaced; regex = g_regex_new(pattern, G_REGEX_MULTILINE, 0, error); if (!regex) return NULL; replaced = g_regex_replace(regex, string, -1, 0, replacement, 0, error); g_regex_unref(regex); return replaced; } const gchar * cut_utils_get_fixture_data (CutTestContext *context, const gchar **fixture_data_path, gsize *size, const char *path, ...) { const gchar *data; va_list args; va_start(args, path); data = cut_utils_get_fixture_data_va_list(context, fixture_data_path, size, path, args); va_end(args); return data; } const gchar * cut_utils_get_fixture_data_va_list (CutTestContext *context, const gchar **fixture_data_path, gsize *size, const gchar *path, va_list args) { GString *fixture_data; fixture_data = gcut_utils_get_fixture_data_va_list(context, fixture_data_path, path, args); if (!fixture_data) return NULL; if (size) *size = fixture_data->len; return fixture_data->str; } void cut_utils_append_indent (GString *string, guint size) { guint i; for (i = 0; i < size; i++) g_string_append_c(string, ' '); } void cut_utils_append_xml_element_with_value (GString *string, guint indent, const gchar *element_name, const gchar *value) { gchar *escaped; cut_utils_append_indent(string, indent); escaped = g_markup_printf_escaped("<%s>%s\n", element_name, value, element_name); g_string_append(string, escaped); g_free(escaped); } void cut_utils_append_xml_element_with_boolean_value (GString *string, guint indent, const gchar *element_name, gboolean boolean) { cut_utils_append_xml_element_with_value(string, indent, element_name, boolean ? "true" : "false"); } gchar ** cut_utils_strv_concat (const gchar **string_array, ...) { guint length, i; guint args_length = 0; va_list args; gchar *string; gchar **new_string_array; if (!string_array) return NULL; length = g_strv_length((gchar **)string_array); va_start(args, string_array); string = va_arg(args, gchar*); while (string) { args_length++; string = va_arg(args, gchar*); } va_end(args); new_string_array = g_new(gchar*, length + args_length + 1); for (i = 0; i < length; i++) { new_string_array[i] = g_strdup(string_array[i]); } va_start(args, string_array); string = va_arg(args, gchar*); while (string) { new_string_array[i] = g_strdup(string); i++; string = va_arg(args, gchar*); } va_end(args); new_string_array[i] = NULL; return new_string_array; } void cut_utils_close_pipe (int *pipe, CutPipeMode mode) { if (pipe[mode] == -1) return; close(pipe[mode]); pipe[mode] = -1; } const gchar * cut_utils_get_cutter_command_path (void) { const gchar *cutter_command; cutter_command = g_getenv("CUTTER"); if (cutter_command) return cutter_command; cutter_command = cut_get_cutter_command_path(); if (cutter_command) return cutter_command; return g_get_prgname(); } gchar * cut_utils_build_path (const gchar *path, ...) { char *built_path; va_list args; va_start(args, path); built_path = cut_utils_build_path_va_list(path, args); va_end(args); return built_path; } gchar * cut_utils_build_path_va_list (const gchar *path, va_list args) { GArray *elements; gchar *element, *concatenated_path; if (!path) return NULL; elements = g_array_new(TRUE, FALSE, sizeof(char *)); g_array_append_val(elements, path); while ((element = va_arg(args, gchar *))) { g_array_append_val(elements, element); } concatenated_path = cut_utils_build_path_array((const gchar **)(elements->data)); g_array_free(elements, TRUE); return concatenated_path; } gchar * cut_utils_build_path_array (const gchar **paths) { return g_build_filenamev((gchar **)paths); } gchar * cut_utils_expand_path (const gchar *path) { if (!path) return NULL; if (g_path_is_absolute(path)) { return g_strdup(path); } else { gchar *current_dir, *full_path; current_dir = g_get_current_dir(); full_path = g_build_filename(current_dir, path, NULL); g_free(current_dir); return full_path; } } gchar * cut_utils_expand_path_va_list (const gchar *path, va_list args) { gchar *concatenated_path, *expanded_path; if (!path) return NULL; concatenated_path = cut_utils_build_path_va_list(path, args); expanded_path = cut_utils_expand_path(concatenated_path); g_free(concatenated_path); return expanded_path; } gboolean cut_utils_remove_path (const char *path, GError **error) { if (!g_file_test(path, G_FILE_TEST_EXISTS)) { g_set_error(error, G_FILE_ERROR, G_FILE_ERROR_NOENT, "path doesn't exist: %s", path); return FALSE; } if (g_file_test(path, G_FILE_TEST_IS_DIR)) { if (g_rmdir(path) == -1) { g_set_error(error, G_FILE_ERROR, g_file_error_from_errno(errno), "can't remove directory: %s", path); return FALSE; } } else { if (g_unlink(path) == -1) { g_set_error(error, G_FILE_ERROR, g_file_error_from_errno(errno), "can't remove path: %s", path); return FALSE; } } return TRUE; } gboolean cut_utils_remove_path_recursive (const char *path, GError **error) { if (g_file_test(path, G_FILE_TEST_IS_DIR)) { GDir *dir; const gchar *name; gboolean success = TRUE; dir = g_dir_open(path, 0, error); if (!dir) return FALSE; while ((name = g_dir_read_name(dir))) { gchar *full_path; full_path = g_build_filename(path, name, NULL); success = cut_utils_remove_path_recursive(full_path, error); g_free(full_path); if (!success) break; } g_dir_close(dir); if (!success) return FALSE; } return cut_utils_remove_path(path, error); } void cut_utils_remove_path_recursive_force (const gchar *path) { cut_utils_remove_path_recursive(path, NULL); } void cut_utils_make_directory_recursive_force (const gchar *path) { g_mkdir_with_parents(path, 0700); } gchar * cut_utils_append_diff (const gchar *message, const gchar *from, const gchar *to) { gchar *diff, *result; diff = cut_diff_readable(from, to); if (cut_diff_readable_is_interested(diff)) { result = g_strdup_printf("%s\n" "\n" "diff:\n" "%s", message, diff); if (cut_diff_readable_need_fold(diff)) { gchar *folded_diff, *original_result; original_result = result; folded_diff = cut_diff_readable_folded(from, to); result = g_strdup_printf("%s\n" "\n" "folded diff:\n" "%s", original_result, folded_diff); g_free(original_result); g_free(folded_diff); } } else { result = g_strdup(message); } g_free(diff); return result; } gchar * cut_utils_fold (const gchar *string) { GRegex *fold_re; GArray *folded_lines; gchar **lines, **line; gchar *folded_string; guint i; fold_re = g_regex_new("(.{78})", 0, 0, NULL); folded_lines = g_array_new(TRUE, FALSE, sizeof(gchar *)); lines = g_regex_split_simple("\r?\n", string, 0, 0); for (line = lines; *line; line++) { gchar *folded_line; folded_line = g_regex_replace(fold_re, *line, -1, 0, "\\1\n", 0, NULL); g_array_append_val(folded_lines, folded_line); } g_strfreev(lines); folded_string = g_strjoinv("\n", (gchar **)(folded_lines->data)); for (i = 0; i < folded_lines->len; i++) { gchar *folded_line; folded_line = g_array_index(folded_lines, gchar *, i); g_free(folded_line); } g_array_free(folded_lines, TRUE); g_regex_unref(fold_re); return folded_string; } CutSubProcess * cut_utils_take_new_sub_process (const char *test_directory, CutTestContext *test_context) { CutSubProcess *sub_process; sub_process = cut_sub_process_new(test_directory, test_context); cut_test_context_take_g_object(test_context, G_OBJECT(sub_process)); return sub_process; } CutSubProcessGroup * cut_utils_take_new_sub_process_group (CutTestContext *test_context) { CutSubProcessGroup *group; group = cut_sub_process_group_new(test_context); cut_test_context_take_g_object(test_context, G_OBJECT(group)); return group; } typedef enum { GDB_BACKTRACE_START, GDB_BACKTRACE_IN, GDB_BACKTRACE_FUNCTION, GDB_BACKTRACE_ARGUMENTS, GDB_BACKTRACE_ARGUMENTS_END, GDB_BACKTRACE_AT, GDB_BACKTRACE_LINE } GdbBacktraceState; GList * cut_utils_parse_gdb_backtrace (const gchar *gdb_backtrace) { GList *backtraces = NULL; while (gdb_backtrace && gdb_backtrace[0]) { CutBacktraceEntry *entry; gchar *file = NULL; guint line = 0; gchar *function = NULL; gchar *info = NULL; const gchar *start_point = NULL; GdbBacktraceState state = GDB_BACKTRACE_START; while (gdb_backtrace[0] && gdb_backtrace[0] != '\n') { switch (state) { case GDB_BACKTRACE_START: if (gdb_backtrace[0] == 'i' && gdb_backtrace[1] == 'n') { gdb_backtrace++; state = GDB_BACKTRACE_IN; } break; case GDB_BACKTRACE_IN: if (start_point) { if (gdb_backtrace[0] == ' ') { function = g_strndup(start_point, gdb_backtrace - start_point); state = GDB_BACKTRACE_ARGUMENTS; start_point = NULL; } } else { if (gdb_backtrace[0] != ' ') start_point = gdb_backtrace; } break; case GDB_BACKTRACE_ARGUMENTS: if (gdb_backtrace[0] == ')') state = GDB_BACKTRACE_ARGUMENTS_END; break; case GDB_BACKTRACE_ARGUMENTS_END: if (gdb_backtrace[0] == 'a' && gdb_backtrace[1] == 't') { gdb_backtrace ++; state = GDB_BACKTRACE_AT; } break; case GDB_BACKTRACE_AT: if (start_point) { if (gdb_backtrace[0] == ':') { file = g_strndup(start_point, gdb_backtrace - start_point); state = GDB_BACKTRACE_LINE; start_point = NULL; } } else { if (gdb_backtrace[0] != ' ') start_point = gdb_backtrace; } break; case GDB_BACKTRACE_LINE: if (start_point) { if (gdb_backtrace[1] == '\n') { line = atoi(start_point); start_point = NULL; } } else { start_point = gdb_backtrace; } break; default: break; } gdb_backtrace++; } entry = cut_backtrace_entry_new(file ? file : "unknown", line, function, info); backtraces = g_list_append(backtraces, entry); if (file) g_free(file); if (function) g_free(function); if (info) g_free(info); gdb_backtrace++; } return backtraces; } gchar * cut_utils_double_to_string (gdouble value) { gint i; gchar *string; string = g_strdup_printf("%f", value); for (i = 0; string[i]; i++) { if (string[i] == ',') string[i] = '.'; } return string; } gint cut_utils_compare_string (gconstpointer data1, gconstpointer data2) { if (data1 == NULL && data2 == NULL) return 0; if (data1 == NULL) return -1; if (data2 == NULL) return 1; return strcmp(data1, data2); } gint cut_utils_compare_direct (gconstpointer data1, gconstpointer data2) { guint value1, value2; value1 = GPOINTER_TO_UINT(data1); value2 = GPOINTER_TO_UINT(data2); if (value1 == value2) { return 0; } else if (value1 < value2) { return -1; } else { return 1; } } #ifdef G_OS_WIN32 static gchar *win32_base_path = NULL; const gchar * cut_win32_base_path (void) { if (win32_base_path) return win32_base_path; win32_base_path = g_win32_get_package_installation_directory_of_module(NULL); return win32_base_path; } static gchar *win32_icons_dir = NULL; const gchar * cut_win32_icons_dir (void) { if (win32_icons_dir) return win32_icons_dir; win32_icons_dir = g_build_filename(cut_win32_base_path(), "share", PACKAGE, "icons", NULL); return win32_icons_dir; } static gchar *win32_ui_data_dir = NULL; const gchar * cut_win32_ui_data_dir (void) { if (win32_ui_data_dir) return win32_ui_data_dir; win32_ui_data_dir = g_build_filename(cut_win32_base_path(), "share", PACKAGE, "ui", NULL); return win32_ui_data_dir; } gchar * cut_win32_build_module_dir_name (const gchar *type) { return g_build_filename(cut_win32_base_path(), "lib", PACKAGE, "module", type, NULL); } gchar * cut_win32_build_factory_module_dir_name (const gchar *type) { gchar *module_dir, *factory_module_dir; module_dir = cut_win32_build_module_dir_name("factory"); factory_module_dir = g_build_filename(module_dir, type, NULL); g_free(module_dir); return factory_module_dir; } gboolean cut_win32_kill_process (GPid pid, guint exit_code) { return TerminateProcess(pid, exit_code) ? TRUE : FALSE; } #endif /* vi:ts=4:nowrap:ai:expandtab:sw=4 */