1 /* -*- Mode: C; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * Copyright (C) 2007-2011 Kouhei Sutou <kou@clear-code.com>
4 *
5 * This library is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 *
18 */
19
20 #ifdef HAVE_CONFIG_H
21 # include <config.h>
22 #endif /* HAVE_CONFIG_H */
23
24 #include <string.h>
25 #include <math.h>
26 #ifdef HAVE_UNISTD_H
27 # include <unistd.h>
28 #endif
29 #include <glib.h>
30 #include <glib/gstdio.h>
31 #ifdef G_OS_WIN32
32 # include <winsock2.h>
33 # include <io.h>
34 # define close _close
35 #endif
36
37 #include <errno.h>
38
39 #include "cut-utils.h"
40 #include "cut-sub-process.h"
41 #include "cut-sub-process-group.h"
42 #include "cut-readable-differ.h"
43 #include "cut-main.h"
44 #include "cut-backtrace-entry.h"
45 #include "../gcutter/gcut-public.h"
46 #include "../gcutter/gcut-error.h"
47 #include "../gcutter/gcut-assertions-helper.h"
48
49 #ifndef CUT_DISABLE_SOCKET_SUPPORT
50 # ifdef CUT_HAVE_WINSOCK2_H
51 # include <winsock2.h>
52 # include <ws2tcpip.h>
53 # else
54 # include <sys/types.h>
55 # include <sys/socket.h>
56 # include <netinet/in.h>
57 # include <arpa/inet.h>
58 # ifdef HAVE_SYS_UN_H
59 # include <sys/un.h>
60 # endif
61 # endif
62 #endif
63
64 gchar *
cut_utils_create_regex_pattern(const gchar * string)65 cut_utils_create_regex_pattern (const gchar *string)
66 {
67 gchar *pattern;
68
69 if (!string) {
70 pattern = g_strdup(".*");
71 } else if (strlen(string) > 1 &&
72 g_str_has_prefix(string, "/") && g_str_has_suffix(string, "/")) {
73 pattern = g_strndup(string + 1, strlen(string) - 2);
74 } else {
75 gchar *escaped_string;
76 escaped_string = g_regex_escape_string(string, -1);
77 pattern = g_strdup_printf("^%s$", escaped_string);
78 g_free(escaped_string);
79 }
80
81 return pattern;
82 }
83
84 GList *
cut_utils_filter_to_regexs(const gchar ** filter)85 cut_utils_filter_to_regexs (const gchar **filter)
86 {
87 GList *regexs = NULL;
88
89 for (; *filter; filter++) {
90 GRegex *regex;
91 gchar *pattern;
92 GError *error = NULL;
93
94 if (*filter[0] == '\0')
95 continue;
96
97 pattern = cut_utils_create_regex_pattern(*filter);
98 regex = g_regex_new(pattern, 0, 0, &error);
99 if (regex) {
100 regexs = g_list_prepend(regexs, regex);
101 } else {
102 cut_utils_report_error(error);
103 }
104 g_free(pattern);
105 }
106
107 return regexs;
108 }
109
110 gboolean
cut_utils_filter_match(GList * regexs,const gchar * name)111 cut_utils_filter_match (GList *regexs, const gchar *name)
112 {
113 GList *node;
114
115 for (node = regexs; node; node = g_list_next(node)) {
116 GRegex *regex = node->data;
117
118 if (g_regex_match(regex, name, 0, NULL))
119 return TRUE;
120 }
121
122 return FALSE;
123 }
124
125 gchar *
cut_utils_inspect_memory(const void * memory,size_t size)126 cut_utils_inspect_memory (const void *memory, size_t size)
127 {
128 const guchar *binary = memory;
129 GString *buffer;
130 size_t i, n_printable_characters;
131 size_t max_size = 1024;
132
133 if (memory == NULL || size == 0)
134 return g_strdup("(null)");
135
136 buffer = g_string_sized_new(size * strlen("0xXX") +
137 (size - 1) * strlen(" ") +
138 strlen(": ") +
139 size);
140 max_size = MIN(size, max_size);
141 n_printable_characters = 0;
142 for (i = 0; i < max_size; i++) {
143 g_string_append_printf(buffer, "0x%02x ", binary[i]);
144 if (g_ascii_isprint(binary[i]))
145 n_printable_characters++;
146 }
147 if (size > max_size)
148 g_string_append(buffer, "... ");
149
150 if (n_printable_characters >= max_size * 0.3) {
151 g_string_overwrite(buffer, buffer->len - 1, ": ");
152 for (i = 0; i < max_size; i++) {
153 if (g_ascii_isprint(binary[i])) {
154 g_string_append_c(buffer, binary[i]);
155 } else {
156 g_string_append_c(buffer, '.');
157 }
158 }
159 if (size > max_size)
160 g_string_append(buffer, "...");
161 } else {
162 g_string_truncate(buffer, buffer->len - 1);
163 }
164
165 return g_string_free(buffer, FALSE);
166 }
167
168 gboolean
cut_utils_equal_string(const gchar * string1,const gchar * string2)169 cut_utils_equal_string (const gchar *string1, const gchar *string2)
170 {
171 if (string1 == string2)
172 return TRUE;
173
174 if (string1 == NULL || string2 == NULL)
175 return FALSE;
176
177 return g_str_equal(string1, string2);
178 }
179
180 gboolean
cut_utils_equal_substring(const gchar * string1,const gchar * string2,size_t length)181 cut_utils_equal_substring (const gchar *string1, const gchar *string2,
182 size_t length)
183 {
184 if (string1 == string2)
185 return TRUE;
186
187 if (string1 == NULL || string2 == NULL)
188 return FALSE;
189
190 return strncmp(string1, string2, length) == 0;
191 }
192
193 gboolean
cut_utils_equal_double(gdouble double1,gdouble double2,gdouble error)194 cut_utils_equal_double (gdouble double1, gdouble double2, gdouble error)
195 {
196 return fabs(double1 - double2) <= error;
197 }
198
199 gboolean
cut_utils_equal_string_array(gchar ** strings1,gchar ** strings2)200 cut_utils_equal_string_array (gchar **strings1, gchar **strings2)
201 {
202 gint i, length;
203
204 if (!strings1 && !strings2)
205 return TRUE;
206
207 if (!strings1 || !strings2)
208 return FALSE;
209
210 length = g_strv_length(strings1);
211
212 if (length != g_strv_length(strings2))
213 return FALSE;
214
215 for (i = 0; i < length; i++) {
216 if (strcmp(strings1[i], strings2[i]))
217 return FALSE;
218 }
219
220 return TRUE;
221 }
222
223 static void
cut_utils_inspect_string_to_gstring(GString * inspected,const gchar * string)224 cut_utils_inspect_string_to_gstring (GString *inspected, const gchar *string)
225 {
226 if (!string) {
227 g_string_append(inspected, "(null)");
228 return;
229 }
230
231 g_string_append_c(inspected, '"');
232 for (; string[0]; string++) {
233 switch (string[0]) {
234 case '"':
235 g_string_append(inspected, "\\\"");
236 break;
237 case '\\':
238 g_string_append(inspected, "\\\\");
239 break;
240 default:
241 g_string_append_c(inspected, string[0]);
242 break;
243 }
244 }
245 g_string_append_c(inspected, '"');
246 }
247
248 gchar *
cut_utils_inspect_string_array(gchar ** strings)249 cut_utils_inspect_string_array (gchar **strings)
250 {
251 GString *inspected;
252 gchar **string, **next_string;
253
254 if (!strings)
255 return g_strdup("(null)");
256
257 inspected = g_string_new("[");
258 string = strings;
259 while (*string) {
260 cut_utils_inspect_string_to_gstring(inspected, *string);
261 next_string = string + 1;
262 if (*next_string)
263 g_string_append(inspected, ", ");
264 string = next_string;
265 }
266 g_string_append(inspected, "]");
267
268 return g_string_free(inspected, FALSE);
269 }
270
271 gchar *
cut_utils_inspect_string(const gchar * string)272 cut_utils_inspect_string (const gchar *string)
273 {
274 GString *inspected;
275
276 inspected = g_string_new(NULL);
277 cut_utils_inspect_string_to_gstring(inspected, string);
278 return g_string_free(inspected, FALSE);
279 }
280
281 #ifndef CUT_DISABLE_SOCKET_SUPPORT
282 gboolean
cut_utils_equal_sockaddr(const struct sockaddr * address1,const struct sockaddr * address2)283 cut_utils_equal_sockaddr (const struct sockaddr *address1,
284 const struct sockaddr *address2)
285 {
286 if (address1 == address2)
287 return TRUE;
288 if (!address1 || !address2)
289 return FALSE;
290 if (address1->sa_family != address2->sa_family)
291 return FALSE;
292
293 switch (address1->sa_family) {
294 #ifdef HAVE_SYS_UN_H
295 case AF_UNIX:
296 {
297 struct sockaddr_un *address_unix1 = (struct sockaddr_un *)address1;
298 struct sockaddr_un *address_unix2 = (struct sockaddr_un *)address2;
299
300 return cut_utils_equal_string(address_unix1->sun_path,
301 address_unix2->sun_path);
302 break;
303 }
304 #endif
305 case AF_INET:
306 {
307 struct sockaddr_in *address_inet1 = (struct sockaddr_in *)address1;
308 struct sockaddr_in *address_inet2 = (struct sockaddr_in *)address2;
309
310 if (address_inet1->sin_addr.s_addr != address_inet2->sin_addr.s_addr)
311 return FALSE;
312 if (address_inet1->sin_port != address_inet2->sin_port)
313 return FALSE;
314
315 return TRUE;
316 break;
317 }
318 case AF_INET6:
319 {
320 struct sockaddr_in6 *address_inet6_1 = (struct sockaddr_in6 *)address1;
321 struct sockaddr_in6 *address_inet6_2 = (struct sockaddr_in6 *)address2;
322
323 if (memcmp(address_inet6_1->sin6_addr.s6_addr,
324 address_inet6_2->sin6_addr.s6_addr,
325 sizeof(address_inet6_1->sin6_addr.s6_addr)) != 0)
326 return FALSE;
327 if (address_inet6_1->sin6_port != address_inet6_2->sin6_port)
328 return FALSE;
329
330 return TRUE;
331 break;
332 }
333 case AF_UNSPEC:
334 return TRUE;
335 break;
336 default:
337 return FALSE;
338 break;
339 }
340
341 return FALSE;
342 }
343
344 #ifdef G_OS_WIN32
345 # if !defined(NTDDI_VERSION) || (NTDDI_VERSION < NTDDI_LONGHORN)
346 static const char *
inet_ntop(int address_family,const void * source,char * destination,socklen_t destination_length)347 inet_ntop (int address_family, const void *source,
348 char *destination, socklen_t destination_length)
349 {
350 DWORD socket_address_length;
351 DWORD winsock_destination_length = destination_length;
352
353 switch (address_family) {
354 case AF_INET:
355 socket_address_length = sizeof(struct sockaddr_in);
356 break;
357 case AF_INET6:
358 socket_address_length = sizeof(struct sockaddr_in6);
359 break;
360 default:
361 return NULL;
362 break;
363 }
364
365 if (WSAAddressToString((LPSOCKADDR)source, socket_address_length, NULL,
366 destination, &winsock_destination_length)) {
367 return NULL;
368 } else {
369 return destination;
370 }
371 }
372 # endif
373 #endif
374
375 gchar *
cut_utils_inspect_sockaddr(const struct sockaddr * address)376 cut_utils_inspect_sockaddr (const struct sockaddr *address)
377 {
378 gchar *spec = NULL;
379
380 if (!address)
381 return g_strdup("(null)");
382
383 switch (address->sa_family) {
384 #ifdef HAVE_SYS_UN_H
385 case AF_UNIX:
386 {
387 struct sockaddr_un *address_unix = (struct sockaddr_un *)address;
388 spec = g_strdup_printf("unix:%s", address_unix->sun_path);
389 break;
390 }
391 #endif
392 case AF_INET:
393 {
394 struct sockaddr_in *address_inet = (struct sockaddr_in *)address;
395 gchar ip_address_string[INET_ADDRSTRLEN];
396
397 if (inet_ntop(AF_INET, &address_inet->sin_addr,
398 (gchar *)ip_address_string, INET_ADDRSTRLEN)) {
399 spec = g_strdup_printf("inet:%s:%d",
400 ip_address_string,
401 g_ntohs(address_inet->sin_port));
402 }
403 break;
404 }
405 case AF_INET6:
406 {
407 struct sockaddr_in6 *address_inet6 = (struct sockaddr_in6 *)address;
408 gchar ip_address_string[INET6_ADDRSTRLEN];
409
410 if (inet_ntop(AF_INET6, &address_inet6->sin6_addr,
411 (gchar *)ip_address_string, INET6_ADDRSTRLEN)) {
412 spec = g_strdup_printf("inet6:[%s]:%d",
413 ip_address_string,
414 g_ntohs(address_inet6->sin6_port));
415 }
416 break;
417 }
418 case AF_UNSPEC:
419 spec = g_strdup("unknown");
420 break;
421 default:
422 spec = g_strdup_printf("unexpected:%d", address->sa_family);
423 break;
424 }
425
426 return spec;
427 }
428 #endif
429
430 gboolean
cut_utils_path_exist(const gchar * path)431 cut_utils_path_exist (const gchar *path)
432 {
433 return g_file_test(path, G_FILE_TEST_EXISTS);
434 }
435
436 gboolean
cut_utils_regex_match(const gchar * pattern,const gchar * string)437 cut_utils_regex_match (const gchar *pattern, const gchar *string)
438 {
439 return g_regex_match_simple(pattern, string, G_REGEX_MULTILINE, 0);
440 }
441
442 gchar *
cut_utils_regex_replace(const gchar * pattern,const gchar * string,const gchar * replacement,GError ** error)443 cut_utils_regex_replace (const gchar *pattern, const gchar *string,
444 const gchar *replacement, GError **error)
445 {
446 GRegex *regex;
447 gchar *replaced;
448
449 regex = g_regex_new(pattern, G_REGEX_MULTILINE, 0, error);
450 if (!regex)
451 return NULL;
452
453 replaced = g_regex_replace(regex, string, -1, 0, replacement, 0, error);
454 g_regex_unref(regex);
455
456 return replaced;
457 }
458
459 const gchar *
cut_utils_get_fixture_data(CutTestContext * context,const gchar ** fixture_data_path,gsize * size,const char * path,...)460 cut_utils_get_fixture_data (CutTestContext *context,
461 const gchar **fixture_data_path,
462 gsize *size,
463 const char *path,
464 ...)
465 {
466 const gchar *data;
467 va_list args;
468
469 va_start(args, path);
470 data = cut_utils_get_fixture_data_va_list(context, fixture_data_path, size,
471 path, args);
472 va_end(args);
473
474 return data;
475 }
476
477 const gchar *
cut_utils_get_fixture_data_va_list(CutTestContext * context,const gchar ** fixture_data_path,gsize * size,const gchar * path,va_list args)478 cut_utils_get_fixture_data_va_list (CutTestContext *context,
479 const gchar **fixture_data_path,
480 gsize *size,
481 const gchar *path,
482 va_list args)
483 {
484 GString *fixture_data;
485
486 fixture_data = gcut_utils_get_fixture_data_va_list(context,
487 fixture_data_path,
488 path, args);
489 if (!fixture_data)
490 return NULL;
491
492 if (size)
493 *size = fixture_data->len;
494
495 return fixture_data->str;
496 }
497
498 void
cut_utils_append_indent(GString * string,guint size)499 cut_utils_append_indent (GString *string, guint size)
500 {
501 guint i;
502
503 for (i = 0; i < size; i++)
504 g_string_append_c(string, ' ');
505 }
506
507 void
cut_utils_append_xml_element_with_value(GString * string,guint indent,const gchar * element_name,const gchar * value)508 cut_utils_append_xml_element_with_value (GString *string, guint indent,
509 const gchar *element_name,
510 const gchar *value)
511 {
512 gchar *escaped;
513
514 cut_utils_append_indent(string, indent);
515 escaped = g_markup_printf_escaped("<%s>%s</%s>\n",
516 element_name,
517 value,
518 element_name);
519 g_string_append(string, escaped);
520 g_free(escaped);
521 }
522
523 void
cut_utils_append_xml_element_with_boolean_value(GString * string,guint indent,const gchar * element_name,gboolean boolean)524 cut_utils_append_xml_element_with_boolean_value (GString *string, guint indent,
525 const gchar *element_name,
526 gboolean boolean)
527 {
528 cut_utils_append_xml_element_with_value(string, indent, element_name,
529 boolean ? "true" : "false");
530 }
531
532 gchar **
cut_utils_strv_concat(const gchar ** string_array,...)533 cut_utils_strv_concat (const gchar **string_array, ...)
534 {
535 guint length, i;
536 guint args_length = 0;
537 va_list args;
538 gchar *string;
539 gchar **new_string_array;
540
541 if (!string_array)
542 return NULL;
543
544 length = g_strv_length((gchar **)string_array);
545 va_start(args, string_array);
546 string = va_arg(args, gchar*);
547 while (string) {
548 args_length++;
549 string = va_arg(args, gchar*);
550 }
551 va_end(args);
552
553 new_string_array = g_new(gchar*, length + args_length + 1);
554
555 for (i = 0; i < length; i++) {
556 new_string_array[i] = g_strdup(string_array[i]);
557 }
558
559 va_start(args, string_array);
560 string = va_arg(args, gchar*);
561 while (string) {
562 new_string_array[i] = g_strdup(string);
563 i++;
564 string = va_arg(args, gchar*);
565 }
566 va_end(args);
567
568 new_string_array[i] = NULL;
569
570 return new_string_array;
571 }
572
573 void
cut_utils_close_pipe(int * pipe,CutPipeMode mode)574 cut_utils_close_pipe (int *pipe, CutPipeMode mode)
575 {
576 if (pipe[mode] == -1)
577 return;
578 close(pipe[mode]);
579 pipe[mode] = -1;
580 }
581
582 const gchar *
cut_utils_get_cutter_command_path(void)583 cut_utils_get_cutter_command_path (void)
584 {
585 const gchar *cutter_command;
586
587 cutter_command = g_getenv("CUTTER");
588 if (cutter_command)
589 return cutter_command;
590
591 cutter_command = cut_get_cutter_command_path();
592 if (cutter_command)
593 return cutter_command;
594
595 return g_get_prgname();
596 }
597
598 gchar *
cut_utils_build_path(const gchar * path,...)599 cut_utils_build_path (const gchar *path, ...)
600 {
601 char *built_path;
602 va_list args;
603
604 va_start(args, path);
605 built_path = cut_utils_build_path_va_list(path, args);
606 va_end(args);
607
608 return built_path;
609 }
610
611 gchar *
cut_utils_build_path_va_list(const gchar * path,va_list args)612 cut_utils_build_path_va_list (const gchar *path, va_list args)
613 {
614 GArray *elements;
615 gchar *element, *concatenated_path;
616
617 if (!path)
618 return NULL;
619
620 elements = g_array_new(TRUE, FALSE, sizeof(char *));
621
622 g_array_append_val(elements, path);
623 while ((element = va_arg(args, gchar *))) {
624 g_array_append_val(elements, element);
625 }
626 concatenated_path =
627 cut_utils_build_path_array((const gchar **)(elements->data));
628 g_array_free(elements, TRUE);
629
630 return concatenated_path;
631 }
632
633 gchar *
cut_utils_build_path_array(const gchar ** paths)634 cut_utils_build_path_array (const gchar **paths)
635 {
636 return g_build_filenamev((gchar **)paths);
637 }
638
639 gchar *
cut_utils_expand_path(const gchar * path)640 cut_utils_expand_path (const gchar *path)
641 {
642 if (!path)
643 return NULL;
644
645 if (g_path_is_absolute(path)) {
646 return g_strdup(path);
647 } else {
648 gchar *current_dir, *full_path;
649
650 current_dir = g_get_current_dir();
651 full_path = g_build_filename(current_dir, path, NULL);
652 g_free(current_dir);
653
654 return full_path;
655 }
656 }
657
658 gchar *
cut_utils_expand_path_va_list(const gchar * path,va_list args)659 cut_utils_expand_path_va_list (const gchar *path, va_list args)
660 {
661 gchar *concatenated_path, *expanded_path;
662
663 if (!path)
664 return NULL;
665
666 concatenated_path = cut_utils_build_path_va_list(path, args);
667 expanded_path = cut_utils_expand_path(concatenated_path);
668 g_free(concatenated_path);
669 return expanded_path;
670 }
671
672 gboolean
cut_utils_remove_path(const char * path,GError ** error)673 cut_utils_remove_path (const char *path, GError **error)
674 {
675 if (!g_file_test(path, G_FILE_TEST_EXISTS)) {
676 g_set_error(error, G_FILE_ERROR, G_FILE_ERROR_NOENT,
677 "path doesn't exist: %s", path);
678 return FALSE;
679 }
680
681 if (g_file_test(path, G_FILE_TEST_IS_DIR)) {
682 if (g_rmdir(path) == -1) {
683 g_set_error(error, G_FILE_ERROR, g_file_error_from_errno(errno),
684 "can't remove directory: %s", path);
685 return FALSE;
686 }
687 } else {
688 if (g_unlink(path) == -1) {
689 g_set_error(error, G_FILE_ERROR, g_file_error_from_errno(errno),
690 "can't remove path: %s", path);
691 return FALSE;
692 }
693 }
694
695 return TRUE;
696 }
697
698 gboolean
cut_utils_remove_path_recursive(const char * path,GError ** error)699 cut_utils_remove_path_recursive (const char *path, GError **error)
700 {
701 if (g_file_test(path, G_FILE_TEST_IS_DIR)) {
702 GDir *dir;
703 const gchar *name;
704 gboolean success = TRUE;
705
706 dir = g_dir_open(path, 0, error);
707 if (!dir)
708 return FALSE;
709
710 while ((name = g_dir_read_name(dir))) {
711 gchar *full_path;
712
713 full_path = g_build_filename(path, name, NULL);
714 success = cut_utils_remove_path_recursive(full_path, error);
715 g_free(full_path);
716 if (!success)
717 break;
718 }
719
720 g_dir_close(dir);
721
722 if (!success)
723 return FALSE;
724 }
725
726 return cut_utils_remove_path(path, error);
727 }
728
729 void
cut_utils_remove_path_recursive_force(const gchar * path)730 cut_utils_remove_path_recursive_force (const gchar *path)
731 {
732 cut_utils_remove_path_recursive(path, NULL);
733 }
734
735 void
cut_utils_make_directory_recursive_force(const gchar * path)736 cut_utils_make_directory_recursive_force (const gchar *path)
737 {
738 g_mkdir_with_parents(path, 0700);
739 }
740
741 gchar *
cut_utils_append_diff(const gchar * message,const gchar * from,const gchar * to)742 cut_utils_append_diff (const gchar *message, const gchar *from, const gchar *to)
743 {
744 gchar *diff, *result;
745
746 diff = cut_diff_readable(from, to);
747 if (cut_diff_readable_is_interested(diff)) {
748 result = g_strdup_printf("%s\n"
749 "\n"
750 "diff:\n"
751 "%s",
752 message, diff);
753 if (cut_diff_readable_need_fold(diff)) {
754 gchar *folded_diff, *original_result;
755
756 original_result = result;
757 folded_diff = cut_diff_readable_folded(from, to);
758 result = g_strdup_printf("%s\n"
759 "\n"
760 "folded diff:\n"
761 "%s",
762 original_result, folded_diff);
763 g_free(original_result);
764 g_free(folded_diff);
765 }
766 } else {
767 result = g_strdup(message);
768 }
769 g_free(diff);
770
771 return result;
772 }
773
774 gchar *
cut_utils_fold(const gchar * string)775 cut_utils_fold (const gchar *string)
776 {
777 GRegex *fold_re;
778 GArray *folded_lines;
779 gchar **lines, **line;
780 gchar *folded_string;
781 guint i;
782
783 fold_re = g_regex_new("(.{78})", 0, 0, NULL);
784 folded_lines = g_array_new(TRUE, FALSE, sizeof(gchar *));
785
786 lines = g_regex_split_simple("\r?\n", string, 0, 0);
787 for (line = lines; *line; line++) {
788 gchar *folded_line;
789
790 folded_line = g_regex_replace(fold_re, *line, -1, 0, "\\1\n", 0, NULL);
791 g_array_append_val(folded_lines, folded_line);
792 }
793 g_strfreev(lines);
794
795 folded_string = g_strjoinv("\n", (gchar **)(folded_lines->data));
796 for (i = 0; i < folded_lines->len; i++) {
797 gchar *folded_line;
798
799 folded_line = g_array_index(folded_lines, gchar *, i);
800 g_free(folded_line);
801 }
802 g_array_free(folded_lines, TRUE);
803 g_regex_unref(fold_re);
804
805 return folded_string;
806 }
807
808 CutSubProcess *
cut_utils_take_new_sub_process(const char * test_directory,CutTestContext * test_context)809 cut_utils_take_new_sub_process (const char *test_directory,
810 CutTestContext *test_context)
811 {
812 CutSubProcess *sub_process;
813
814 sub_process = cut_sub_process_new(test_directory, test_context);
815 cut_test_context_take_g_object(test_context, G_OBJECT(sub_process));
816 return sub_process;
817 }
818
819 CutSubProcessGroup *
cut_utils_take_new_sub_process_group(CutTestContext * test_context)820 cut_utils_take_new_sub_process_group (CutTestContext *test_context)
821 {
822 CutSubProcessGroup *group;
823
824 group = cut_sub_process_group_new(test_context);
825 cut_test_context_take_g_object(test_context, G_OBJECT(group));
826 return group;
827 }
828
829 typedef enum
830 {
831 GDB_BACKTRACE_START,
832 GDB_BACKTRACE_IN,
833 GDB_BACKTRACE_FUNCTION,
834 GDB_BACKTRACE_ARGUMENTS,
835 GDB_BACKTRACE_ARGUMENTS_END,
836 GDB_BACKTRACE_AT,
837 GDB_BACKTRACE_LINE
838 } GdbBacktraceState;
839
840 GList *
cut_utils_parse_gdb_backtrace(const gchar * gdb_backtrace)841 cut_utils_parse_gdb_backtrace (const gchar *gdb_backtrace)
842 {
843 GList *backtraces = NULL;
844
845 while (gdb_backtrace && gdb_backtrace[0]) {
846 CutBacktraceEntry *entry;
847 gchar *file = NULL;
848 guint line = 0;
849 gchar *function = NULL;
850 gchar *info = NULL;
851 const gchar *start_point = NULL;
852 GdbBacktraceState state = GDB_BACKTRACE_START;
853
854 while (gdb_backtrace[0] && gdb_backtrace[0] != '\n') {
855 switch (state) {
856 case GDB_BACKTRACE_START:
857 if (gdb_backtrace[0] == 'i' && gdb_backtrace[1] == 'n') {
858 gdb_backtrace++;
859 state = GDB_BACKTRACE_IN;
860 }
861 break;
862 case GDB_BACKTRACE_IN:
863 if (start_point) {
864 if (gdb_backtrace[0] == ' ') {
865 function = g_strndup(start_point,
866 gdb_backtrace - start_point);
867 state = GDB_BACKTRACE_ARGUMENTS;
868 start_point = NULL;
869 }
870 } else {
871 if (gdb_backtrace[0] != ' ')
872 start_point = gdb_backtrace;
873 }
874 break;
875 case GDB_BACKTRACE_ARGUMENTS:
876 if (gdb_backtrace[0] == ')')
877 state = GDB_BACKTRACE_ARGUMENTS_END;
878 break;
879 case GDB_BACKTRACE_ARGUMENTS_END:
880 if (gdb_backtrace[0] == 'a' && gdb_backtrace[1] == 't') {
881 gdb_backtrace ++;
882 state = GDB_BACKTRACE_AT;
883 }
884 break;
885 case GDB_BACKTRACE_AT:
886 if (start_point) {
887 if (gdb_backtrace[0] == ':') {
888 file = g_strndup(start_point,
889 gdb_backtrace - start_point);
890 state = GDB_BACKTRACE_LINE;
891 start_point = NULL;
892 }
893 } else {
894 if (gdb_backtrace[0] != ' ')
895 start_point = gdb_backtrace;
896 }
897 break;
898 case GDB_BACKTRACE_LINE:
899 if (start_point) {
900 if (gdb_backtrace[1] == '\n') {
901 line = atoi(start_point);
902 start_point = NULL;
903 }
904 } else {
905 start_point = gdb_backtrace;
906 }
907 break;
908 default:
909 break;
910 }
911 gdb_backtrace++;
912 }
913
914 entry = cut_backtrace_entry_new(file ? file : "unknown",
915 line,
916 function,
917 info);
918 backtraces = g_list_append(backtraces, entry);
919 if (file)
920 g_free(file);
921 if (function)
922 g_free(function);
923 if (info)
924 g_free(info);
925
926 gdb_backtrace++;
927 }
928
929 return backtraces;
930 }
931
932 gchar *
cut_utils_double_to_string(gdouble value)933 cut_utils_double_to_string (gdouble value)
934 {
935 gint i;
936 gchar *string;
937
938 string = g_strdup_printf("%f", value);
939 for (i = 0; string[i]; i++) {
940 if (string[i] == ',')
941 string[i] = '.';
942 }
943
944 return string;
945 }
946
947 gint
cut_utils_compare_string(gconstpointer data1,gconstpointer data2)948 cut_utils_compare_string (gconstpointer data1, gconstpointer data2)
949 {
950 if (data1 == NULL && data2 == NULL)
951 return 0;
952
953 if (data1 == NULL)
954 return -1;
955 if (data2 == NULL)
956 return 1;
957
958 return strcmp(data1, data2);
959 }
960
961 gint
cut_utils_compare_direct(gconstpointer data1,gconstpointer data2)962 cut_utils_compare_direct (gconstpointer data1, gconstpointer data2)
963 {
964 guint value1, value2;
965
966 value1 = GPOINTER_TO_UINT(data1);
967 value2 = GPOINTER_TO_UINT(data2);
968 if (value1 == value2) {
969 return 0;
970 } else if (value1 < value2) {
971 return -1;
972 } else {
973 return 1;
974 }
975 }
976
977 #ifdef G_OS_WIN32
978 static gchar *win32_base_path = NULL;
979
980 const gchar *
cut_win32_base_path(void)981 cut_win32_base_path (void)
982 {
983 if (win32_base_path)
984 return win32_base_path;
985
986 win32_base_path = g_win32_get_package_installation_directory_of_module(NULL);
987
988 return win32_base_path;
989 }
990
991 static gchar *win32_icons_dir = NULL;
992
993 const gchar *
cut_win32_icons_dir(void)994 cut_win32_icons_dir (void)
995 {
996 if (win32_icons_dir)
997 return win32_icons_dir;
998
999 win32_icons_dir = g_build_filename(cut_win32_base_path(), "share", PACKAGE,
1000 "icons", NULL);
1001 return win32_icons_dir;
1002 }
1003
1004 static gchar *win32_ui_data_dir = NULL;
1005
1006 const gchar *
cut_win32_ui_data_dir(void)1007 cut_win32_ui_data_dir (void)
1008 {
1009 if (win32_ui_data_dir)
1010 return win32_ui_data_dir;
1011
1012 win32_ui_data_dir = g_build_filename(cut_win32_base_path(), "share", PACKAGE,
1013 "ui", NULL);
1014 return win32_ui_data_dir;
1015 }
1016
1017 gchar *
cut_win32_build_module_dir_name(const gchar * type)1018 cut_win32_build_module_dir_name (const gchar *type)
1019 {
1020 return g_build_filename(cut_win32_base_path(), "lib", PACKAGE,
1021 "module", type, NULL);
1022 }
1023
1024 gchar *
cut_win32_build_factory_module_dir_name(const gchar * type)1025 cut_win32_build_factory_module_dir_name (const gchar *type)
1026 {
1027 gchar *module_dir, *factory_module_dir;
1028
1029 module_dir = cut_win32_build_module_dir_name("factory");
1030 factory_module_dir = g_build_filename(module_dir, type, NULL);
1031 g_free(module_dir);
1032 return factory_module_dir;
1033 }
1034
1035 gboolean
cut_win32_kill_process(GPid pid,guint exit_code)1036 cut_win32_kill_process (GPid pid, guint exit_code)
1037 {
1038 return TerminateProcess(pid, exit_code) ? TRUE : FALSE;
1039 }
1040 #endif
1041
1042
1043 /*
1044 vi:ts=4:nowrap:ai:expandtab:sw=4
1045 */
1046