debug-manager: Remove weak pointer when needed
[anjuta.git] / libanjuta / anjuta-utils.c
blob36a31db73afd569aaff3c14e73b0f59c7daf3648
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3 * anjuta-utils.c
4 * Copyright (C) Naba Kumar <naba@gnome.org>
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
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 /**
22 * SECTION:anjuta-utils
23 * @title: Utilities
24 * @short_description: Utility functions
25 * @see_also:
26 * @stability: Unstable
27 * @include: libanjuta/anjuta-utils.h
31 #ifdef HAVE_CONFIG_H
32 # include <config.h>
33 #endif
35 #include <errno.h>
36 #include <ctype.h>
37 #include <limits.h>
38 #include <stdlib.h>
39 #include <sys/stat.h>
40 #include <sys/types.h>
41 #include <sys/fcntl.h>
42 #include <sys/termios.h>
43 #include <dirent.h>
44 #include <unistd.h>
45 #include <stdio.h>
46 #include <string.h>
48 #include <gio/gio.h>
49 #include <glib/gi18n.h>
50 #include <glib.h>
51 #include <glib/gstdio.h>
52 #include <gtk/gtk.h>
54 #ifndef G_OS_WIN32
55 #include <pwd.h>
56 #else
57 #define WIN32_MEAN_AND_LEAN
58 #include <windows.h>
59 #endif
61 #include <libanjuta/anjuta-utils.h>
62 #include <libanjuta/anjuta-debug.h>
63 #include <libanjuta/interfaces/ianjuta-editor-cell.h>
65 #define FILE_BUFFER_SIZE 1024
67 static gchar *anjuta_prefix = "anjuta";
69 static void
70 anjuta_util_from_file_to_file (GInputStream *istream,
71 GOutputStream *ostream)
73 gsize bytes = 1;
74 GError *error = NULL;
75 gchar buffer[FILE_BUFFER_SIZE];
77 while (bytes != 0 && bytes != -1)
79 bytes = g_input_stream_read (istream, buffer,
80 sizeof (buffer),
81 NULL, &error);
82 if (error)
83 break;
85 g_output_stream_write (ostream, buffer,
86 bytes,
87 NULL, &error);
88 if (error)
89 break;
92 if (error)
94 g_warning ("%s", error->message);
95 g_error_free (error);
96 error = NULL;
99 if (!g_output_stream_close (ostream, NULL, &error))
101 g_warning ("%s", error->message);
102 g_error_free (error);
103 error = NULL;
105 if (!g_input_stream_close (istream, NULL, &error))
107 g_warning ("%s", error->message);
108 g_error_free (error);
113 * anjuta_util_copy_file:
114 * @src: the file where copy
115 * @dest: the path to copy the @src
116 * @show_error: %TRUE to show a dialog error
118 * Copies @src to @dest and shows a dialog error in case is needed.
120 * Returns: %TRUE if there was an error copying the file.
122 gboolean
123 anjuta_util_copy_file (const gchar * src, const gchar * dest, gboolean show_error)
125 GFile *src_file, *dest_file;
126 GFileInputStream *istream;
127 GFileOutputStream *ostream;
128 GError *error = NULL;
129 gboolean toret = FALSE;
131 src_file = g_file_new_for_path (src);
132 dest_file = g_file_new_for_path (dest);
134 istream = g_file_read (src_file, NULL, &error);
135 if (error)
136 goto free;
138 ostream = g_file_create (dest_file, G_FILE_CREATE_NONE,
139 NULL, &error);
140 if (error)
141 goto free;
143 anjuta_util_from_file_to_file (G_INPUT_STREAM (istream), G_OUTPUT_STREAM (ostream));
145 free: if (error)
147 if (show_error)
148 anjuta_util_dialog_error_system (NULL, error->code,
149 error->message);
151 g_warning ("%s", error->message);
153 toret = TRUE;
156 g_object_unref (src_file);
157 g_object_unref (dest_file);
159 return toret;
162 void
163 anjuta_util_color_from_string (const gchar * val, guint16 * r, guint16 * g, guint16 * b)
165 GdkColor color;
166 if (gdk_color_parse(val, &color))
168 *r = color.red;
169 *g = color.green;
170 *b =color.blue;
174 gchar *
175 anjuta_util_string_from_color (guint16 r, guint16 g, guint16 b)
177 return g_strdup_printf("#%02x%02x%02x", r >> 8, g >> 8, b >> 8);
180 GtkWidget*
181 anjuta_util_button_new_with_stock_image (const gchar* text,
182 const gchar* stock_id)
184 GtkWidget *button;
185 GtkWidget *child;
186 GtkStockItem item;
187 GtkWidget *label;
188 GtkWidget *image;
189 GtkWidget *hbox;
190 GtkWidget *align;
192 button = gtk_button_new ();
194 child = gtk_bin_get_child (GTK_BIN (button));
195 if (child)
196 gtk_container_remove (GTK_CONTAINER (button), child);
198 if (gtk_stock_lookup (stock_id, &item))
200 label = gtk_label_new_with_mnemonic (text);
202 gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
204 image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON);
205 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
207 align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
209 gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
210 gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
212 gtk_container_add (GTK_CONTAINER (button), align);
213 gtk_container_add (GTK_CONTAINER (align), hbox);
214 gtk_widget_show_all (align);
216 return button;
219 label = gtk_label_new_with_mnemonic (text);
220 gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
222 gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
224 gtk_widget_show (label);
225 gtk_container_add (GTK_CONTAINER (button), label);
227 return button;
230 GtkWidget*
231 anjuta_util_dialog_add_button (GtkDialog *dialog, const gchar* text,
232 const gchar* stock_id, gint response_id)
234 GtkWidget *button;
236 g_return_val_if_fail (GTK_IS_DIALOG (dialog), NULL);
237 g_return_val_if_fail (text != NULL, NULL);
238 g_return_val_if_fail (stock_id != NULL, NULL);
240 button = anjuta_util_button_new_with_stock_image (text, stock_id);
241 g_return_val_if_fail (button != NULL, NULL);
243 gtk_widget_set_can_default (button, TRUE);
245 gtk_widget_show (button);
247 gtk_dialog_add_action_widget (dialog, button, response_id);
249 return button;
252 void
253 anjuta_util_dialog_error (GtkWindow *parent, const gchar *mesg, ...)
255 gchar* message;
256 va_list args;
257 GtkWidget *dialog;
258 GtkWindow *real_parent;
260 va_start (args, mesg);
261 message = g_strdup_vprintf (mesg, args);
262 va_end (args);
264 if (parent && GTK_IS_WINDOW (parent))
266 real_parent = parent;
268 else
270 real_parent = NULL;
273 // Dialog to be HIG compliant
274 dialog = gtk_message_dialog_new (real_parent,
275 GTK_DIALOG_DESTROY_WITH_PARENT,
276 GTK_MESSAGE_ERROR,
277 GTK_BUTTONS_CLOSE, "%s", message);
278 g_signal_connect (G_OBJECT (dialog), "response",
279 G_CALLBACK (gtk_widget_destroy), NULL);
280 gtk_widget_show (dialog);
281 g_free (message);
284 void
285 anjuta_util_dialog_warning (GtkWindow *parent, const gchar * mesg, ...)
287 gchar* message;
288 va_list args;
289 GtkWidget *dialog;
290 GtkWindow *real_parent;
292 va_start (args, mesg);
293 message = g_strdup_vprintf (mesg, args);
294 va_end (args);
296 if (parent && GTK_IS_WINDOW (parent))
298 real_parent = parent;
300 else
302 real_parent = NULL;
305 // Dialog to be HIG compliant
306 dialog = gtk_message_dialog_new (real_parent,
307 GTK_DIALOG_DESTROY_WITH_PARENT,
308 GTK_MESSAGE_WARNING,
309 GTK_BUTTONS_CLOSE, "%s", message);
310 g_signal_connect (G_OBJECT (dialog), "response",
311 G_CALLBACK (gtk_widget_destroy), NULL);
312 gtk_widget_show (dialog);
313 g_free (message);
316 void
317 anjuta_util_dialog_info (GtkWindow *parent, const gchar * mesg, ...)
319 gchar* message;
320 va_list args;
321 GtkWidget *dialog;
322 GtkWindow *real_parent;
324 va_start (args, mesg);
325 message = g_strdup_vprintf (mesg, args);
326 va_end (args);
328 if (parent && GTK_IS_WINDOW (parent))
330 real_parent = parent;
332 else
334 real_parent = NULL;
336 // Dialog to be HIG compliant
337 dialog = gtk_message_dialog_new (real_parent,
338 GTK_DIALOG_DESTROY_WITH_PARENT,
339 GTK_MESSAGE_INFO,
340 GTK_BUTTONS_CLOSE, "%s", message);
341 g_signal_connect (G_OBJECT (dialog), "response",
342 G_CALLBACK (gtk_widget_destroy), NULL);
343 gtk_widget_show (dialog);
344 g_free (message);
347 void
348 anjuta_util_dialog_error_system (GtkWindow* parent, gint errnum,
349 const gchar * mesg, ... )
351 gchar* message;
352 gchar* tot_mesg;
353 va_list args;
354 GtkWidget *dialog;
355 GtkWindow *real_parent;
357 va_start (args, mesg);
358 message = g_strdup_vprintf (mesg, args);
359 va_end (args);
361 if (0 != errnum) {
362 /* Avoid space in translated string */
363 tot_mesg = g_strconcat (message, "\n", _("System:"), " ",
364 g_strerror(errnum), NULL);
365 g_free (message);
366 } else
367 tot_mesg = message;
369 if (parent && GTK_IS_WINDOW (parent))
371 real_parent = parent;
373 else
375 real_parent = NULL;
377 // Dialog to be HIG compliant
378 dialog = gtk_message_dialog_new (real_parent,
379 GTK_DIALOG_DESTROY_WITH_PARENT,
380 GTK_MESSAGE_ERROR,
381 GTK_BUTTONS_CLOSE, "%s", tot_mesg);
382 g_signal_connect (G_OBJECT (dialog), "response",
383 G_CALLBACK (gtk_widget_destroy), NULL);
384 gtk_widget_show (dialog);
385 g_free (tot_mesg);
388 gboolean
389 anjuta_util_dialog_boolean_question (GtkWindow *parent, gboolean default_to_yes,
390 const gchar *mesg, ...)
392 gchar* message;
393 va_list args;
394 GtkWidget *dialog;
395 gint ret;
396 GtkWindow *real_parent;
398 va_start (args, mesg);
399 message = g_strdup_vprintf (mesg, args);
400 va_end (args);
402 if (parent && GTK_IS_WINDOW (parent))
404 real_parent = parent;
406 else
408 real_parent = NULL;
411 dialog = gtk_message_dialog_new (real_parent,
412 GTK_DIALOG_DESTROY_WITH_PARENT,
413 GTK_MESSAGE_QUESTION,
414 GTK_BUTTONS_YES_NO, "%s", message);
415 if (default_to_yes)
416 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES);
418 ret = gtk_dialog_run (GTK_DIALOG (dialog));
419 gtk_widget_destroy (dialog);
420 g_free (message);
422 return (ret == GTK_RESPONSE_YES);
425 gboolean
426 anjuta_util_dialog_input (GtkWindow *parent, const gchar *prompt,
427 const gchar *default_value, gchar **return_value)
429 GtkWidget *dialog, *label, *frame, *entry, *dialog_vbox, *vbox;
430 gint res;
431 gchar *markup;
432 GtkWindow *real_parent;
434 if (parent && GTK_IS_WINDOW (parent))
436 real_parent = parent;
438 else
440 real_parent = NULL;
443 dialog = gtk_dialog_new_with_buttons (prompt, real_parent,
444 GTK_DIALOG_DESTROY_WITH_PARENT,
445 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
446 GTK_STOCK_OK, GTK_RESPONSE_OK,
447 NULL);
448 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
449 dialog_vbox = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
450 gtk_window_set_default_size (GTK_WINDOW (dialog), 400, -1);
451 gtk_widget_show (dialog_vbox);
453 markup = g_strconcat ("<b>", prompt, "</b>", NULL);
454 label = gtk_label_new (NULL);
455 gtk_label_set_markup (GTK_LABEL (label), markup);
456 gtk_widget_show (label);
457 g_free (markup);
459 frame = gtk_frame_new (NULL);
460 gtk_frame_set_label_widget (GTK_FRAME (frame), label);
461 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
462 gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
463 gtk_widget_show (frame);
464 gtk_box_pack_start (GTK_BOX (dialog_vbox), frame, FALSE, FALSE, 0);
466 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
467 gtk_widget_show (vbox);
468 gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
469 gtk_container_add (GTK_CONTAINER (frame), vbox);
471 entry = gtk_entry_new ();
472 gtk_widget_show (entry);
473 gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
474 gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
475 if (default_value)
476 gtk_entry_set_text (GTK_ENTRY (entry), default_value);
478 res = gtk_dialog_run (GTK_DIALOG (dialog));
480 if (gtk_entry_get_text (GTK_ENTRY (entry)) &&
481 strlen (gtk_entry_get_text (GTK_ENTRY (entry))) > 0)
483 *return_value = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
485 else
487 *return_value = NULL;
489 gtk_widget_destroy (dialog);
490 return (res == GTK_RESPONSE_OK);
493 static void
494 on_install_files_done (GObject *proxy, GAsyncResult *result,
495 gpointer user_data)
497 GError *error = NULL;
498 g_dbus_proxy_call_finish ((GDBusProxy *) proxy, result, &error);
499 if (error)
502 Only dbus error is handled. Rest of the errors are from packagekit
503 which have already been notified to user by packagekit.
505 if (error->domain == G_DBUS_ERROR)
507 const gchar *error_message = NULL;
509 /* Service error which implies packagekit is missing */
510 if (error->code == G_DBUS_ERROR_SERVICE_UNKNOWN)
512 error_message = _("You do not seem to have PackageKit installed. PackageKit is required for installing missing packages. Please install \"packagekit-gnome\" package from your distribution, or install the missing packages manually.");
514 /* General dbus error implies failure to call dbus method */
515 else if (error->code != G_DBUS_ERROR_NO_REPLY)
517 error_message = error->message;
519 if (error_message)
520 anjuta_util_dialog_error (NULL,
521 _("Installation failed: %s"),
522 error_message);
524 g_error_free (error);
528 gboolean
529 anjuta_util_install_files (const gchar * const names)
531 GDBusConnection * connection;
532 GDBusProxy * proxy;
533 guint32 xid = 0;
534 gchar ** pkgv;
536 if (!names)
537 return FALSE;
539 connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
540 if (!connection)
541 return FALSE;
543 proxy = g_dbus_proxy_new_sync (connection,
544 G_DBUS_PROXY_FLAGS_NONE,
545 NULL,
546 "org.freedesktop.PackageKit",
547 "/org/freedesktop/PackageKit",
548 "org.freedesktop.PackageKit.Modify",
549 NULL,
550 NULL);
551 if (!proxy)
552 return FALSE;
554 pkgv = g_strsplit (names, ", ", 0);
555 g_dbus_proxy_call (proxy, "InstallProvideFiles",
556 g_variant_new ("(u^ass)",
557 xid,
558 pkgv,
559 ""),
560 G_DBUS_CALL_FLAGS_NONE,
562 NULL,
563 on_install_files_done,
564 NULL);
565 g_strfreev (pkgv);
566 return TRUE;
569 gboolean
570 anjuta_util_package_is_installed (const gchar * package, gboolean show)
572 const gchar* const argv[] = { "pkg-config", "--exists", package, NULL };
573 int exit_status;
574 GError *err = NULL;
576 if (!g_spawn_sync (NULL, (gchar**)argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
577 NULL, NULL, NULL, &exit_status, &err))
579 if (show)
581 anjuta_util_dialog_error (NULL,
582 _("Failed to run \"%s\". "
583 "The returned error was: \"%s\"."),
584 "pkg-config --exists", err->message);
586 g_error_free (err);
590 if (g_spawn_check_exit_status (exit_status, NULL))
591 return TRUE;
593 if (show)
595 anjuta_util_dialog_error (NULL,
596 _("The \"%s\" package is not installed.\n"
597 "Please install it."), package);
600 return FALSE;
603 gboolean
604 anjuta_util_prog_is_installed (const gchar * prog, gboolean show)
606 gchar* prog_path = g_find_program_in_path (prog);
607 if (prog_path)
609 g_free (prog_path);
610 return TRUE;
612 if (show)
614 anjuta_util_dialog_error (NULL, _("The \"%s\" utility is not installed.\n"
615 "Please install it."), prog);
617 return FALSE;
620 gchar *
621 anjuta_util_get_a_tmp_file (void)
623 static gint count = 0;
624 gchar *filename;
625 const gchar *tmpdir;
627 tmpdir = g_get_tmp_dir ();
628 filename =
629 g_strdup_printf ("%s/anjuta_%d.%d", tmpdir, count++, getpid ());
630 return filename;
633 /* GList of strings operations */
634 GList *
635 anjuta_util_glist_from_string (const gchar *string)
637 gchar *str, *temp, buff[256];
638 GList *list;
639 gchar *word_start, *word_end;
641 list = NULL;
642 temp = g_strdup (string);
643 str = temp;
644 if (!str)
645 return NULL;
647 while (1)
649 gint i;
650 gchar *ptr;
652 /* Remove leading spaces */
653 while (isspace (*str) && *str != '\0')
654 str++;
655 if (*str == '\0')
656 break;
658 /* Find start and end of word */
659 word_start = str;
660 while (!isspace (*str) && *str != '\0')
661 str++;
662 word_end = str;
664 /* Copy the word into the buffer */
665 for (ptr = word_start, i = 0; ptr < word_end; ptr++, i++)
666 buff[i] = *ptr;
667 buff[i] = '\0';
668 if (strlen (buff))
669 list = g_list_append (list, g_strdup (buff));
670 if (*str == '\0')
671 break;
673 if (temp)
674 g_free (temp);
675 return list;
678 /* Prefix the strings */
679 void
680 anjuta_util_glist_strings_prefix (GList * list, const gchar *prefix)
682 GList *node;
683 node = list;
685 g_return_if_fail (prefix != NULL);
686 while (node)
688 gchar* tmp;
689 tmp = node->data;
690 node->data = g_strconcat (prefix, tmp, NULL);
691 if (tmp) g_free (tmp);
692 node = g_list_next (node);
696 /* Suffix the strings */
697 void
698 anjuta_util_glist_strings_sufix (GList * list, const gchar *sufix)
700 GList *node;
701 node = list;
703 g_return_if_fail (sufix != NULL);
704 while (node)
706 gchar* tmp;
707 tmp = node->data;
708 node->data = g_strconcat (tmp, sufix, NULL);
709 if (tmp) g_free (tmp);
710 node = g_list_next (node);
714 /* Duplicate list of strings */
715 GList*
716 anjuta_util_glist_strings_dup (GList * list)
718 GList *node;
719 GList *new_list;
721 new_list = NULL;
722 node = list;
723 while (node)
725 if (node->data)
726 new_list = g_list_append (new_list, g_strdup(node->data));
727 else
728 new_list = g_list_append (new_list, NULL);
729 node = g_list_next (node);
731 return new_list;
734 /* Join list of strings using the given delimiter */
735 gchar*
736 anjuta_util_glist_strings_join (GList * list, gchar *delimiter)
738 GString *joined;
739 gboolean first = TRUE;
740 GList *node;
742 joined = g_string_new (NULL);
743 node = list;
744 while (node)
746 if (node->data)
748 if (!first)
749 g_string_append (joined, delimiter);
750 else
751 first = FALSE;
752 g_string_append (joined, node->data);
754 node = g_list_next (node);
756 if (joined->len > 0)
757 return g_string_free (joined, FALSE);
758 else
759 g_string_free (joined, TRUE);
760 return NULL;
763 gchar*
764 anjuta_util_get_real_path (const gchar *path)
766 if (path != NULL)
768 gchar *result;
769 #ifndef G_OS_WIN32
770 # ifdef PATH_MAX
771 gchar buf[PATH_MAX+1];
773 result = realpath (path, buf);
774 if (result != NULL)
776 *(buf + PATH_MAX) = '\0'; /* ensure a terminator */
777 return g_strdup (buf);
779 # else
780 char *buf;
781 /* the string returned by realpath should be cleaned with
782 free(), not g_free() */
783 buf = realpath (path, NULL);
784 if (buf != NULL)
786 result = g_strdup (buf);
787 free (buf);
788 return result;
790 # endif
791 #else
792 char dummy;
793 int rc, len;
795 /* Get length of path */
796 rc = GetFullPathName (path, 1, &dummy, NULL);
797 if (rc == 0)
799 /* Weird failure */
800 return g_strdup (path);
803 len = rc + 1;
804 result = g_malloc (len);
806 /* Get the real path */
807 rc = GetFullPathName (path, len, result, NULL);
808 if (rc == 0 || rc > len)
810 /* Another weird failure */
811 g_free (result);
812 return g_strdup (path);
815 return result;
816 #endif
818 return NULL;
822 * anjuta_util_get_current_dir:
824 * Get current working directory, unlike g_get_current_dir, keeps symbolic links
825 * in path name.
827 * Returns: The current working directory.
829 gchar*
830 anjuta_util_get_current_dir (void)
832 const gchar *pwd;
834 pwd = g_getenv ("PWD");
835 if (pwd != NULL)
837 return g_strdup (pwd);
839 else
841 return g_get_current_dir ();
845 static gboolean
846 is_valid_scheme_character (char c)
848 return g_ascii_isalnum (c) || c == '+' || c == '-' || c == '.';
851 /* Following RFC 2396, valid schemes are built like:
852 * scheme = alpha *( alpha | digit | "+" | "-" | "." )
854 static gboolean
855 has_valid_scheme (const char *uri)
857 const char *p;
859 p = uri;
861 if (!g_ascii_isalpha (*p))
862 return FALSE;
864 do {
865 p++;
866 } while (is_valid_scheme_character (*p));
868 return *p == ':';
872 * anjuta_util_file_new_for_commandline_arg:
873 * @arg: URI or relative or absolute file path
875 * Create a new file corresponding to arg, unlike g_file_new_for_commandline_arg,
876 * keeps symbolic links in path name.
878 * Returns: (transfer full): A new GFile object
880 GFile *
881 anjuta_util_file_new_for_commandline_arg (const gchar *arg)
883 GFile *file;
884 char *filename;
885 char *current_dir;
887 g_return_val_if_fail (arg != NULL, NULL);
889 if (g_path_is_absolute (arg))
890 return g_file_new_for_path (arg);
892 if (has_valid_scheme (arg))
893 return g_file_new_for_uri (arg);
895 current_dir = anjuta_util_get_current_dir ();
896 filename = g_build_filename (current_dir, arg, NULL);
897 g_free (current_dir);
899 file = g_file_new_for_path (filename);
900 g_free (filename);
902 return file;
906 /* Dedup a list of paths - duplicates are removed from the tail.
907 ** Useful for deduping Recent Files and Recent Projects */
908 GList*
909 anjuta_util_glist_path_dedup(GList *list)
911 GList *nlist = NULL, *tmp, *tmp1;
912 gchar *path;
913 struct stat s;
914 for (tmp = list; tmp; tmp = g_list_next(tmp))
916 path = anjuta_util_get_real_path ((const gchar *) tmp->data);
917 if (path)
919 if (stat (path, &s) != 0)
921 g_free(path);
923 else
925 for (tmp1 = nlist; tmp1; tmp1 = g_list_next(tmp1))
927 if (0 == strcmp((const char *) tmp1->data, path))
929 g_free(path);
930 path = NULL;
931 break;
934 if (path)
935 nlist = g_list_prepend(nlist, path);
939 anjuta_util_glist_strings_free(list);
940 nlist = g_list_reverse(nlist);
941 return nlist;
944 static gint
945 sort_node (gchar* a, gchar *b)
947 if ( !a && !b) return 0;
948 else if (!a) return -1;
949 else if (!b) return 1;
950 return strcmp (a, b);
953 /* Sort the list alphabatically */
954 GList*
955 anjuta_util_glist_strings_sort (GList * list)
957 return g_list_sort(list, (GCompareFunc)sort_node);
960 /* Free the strings and GList */
961 void
962 anjuta_util_glist_strings_free (GList * list)
964 g_list_foreach (list, (GFunc) g_free, NULL);
965 g_list_free (list);
969 anjuta_util_type_from_string (AnjutaUtilStringMap *map, const char *str)
971 int i = 0;
973 while (-1 != map[i].type)
975 if (0 == strcmp(map[i].name, str))
976 return map[i].type;
977 ++ i;
979 return -1;
982 const char*
983 anjuta_util_string_from_type (AnjutaUtilStringMap *map, int type)
985 int i = 0;
986 while (-1 != map[i].type)
988 if (map[i].type == type)
989 return map[i].name;
990 ++ i;
992 return "";
995 GList*
996 anjuta_util_glist_from_map (AnjutaUtilStringMap *map)
998 GList *out_list = NULL;
999 int i = 0;
1000 while (-1 != map[i].type)
1002 out_list = g_list_append(out_list, map[i].name);
1003 ++ i;
1005 return out_list;
1009 GList *
1010 anjuta_util_update_string_list (GList *p_list, const gchar *p_str, gint length)
1012 gint i;
1013 gchar *str;
1014 if (!p_str)
1015 return p_list;
1016 for (i = 0; i < g_list_length (p_list); i++)
1018 str = (gchar *) g_list_nth_data (p_list, i);
1019 if (!str)
1020 continue;
1021 if (strcmp (p_str, str) == 0)
1023 p_list = g_list_remove (p_list, str);
1024 p_list = g_list_prepend (p_list, str);
1025 return p_list;
1028 p_list = g_list_prepend (p_list, g_strdup (p_str));
1029 while (g_list_length (p_list) > length)
1031 str = g_list_nth_data (p_list, g_list_length (p_list) - 1);
1032 p_list = g_list_remove (p_list, str);
1033 g_free (str);
1035 return p_list;
1038 gboolean
1039 anjuta_util_create_dir (const gchar* path)
1041 GFile *dir = g_file_new_for_path (path);
1042 GError *err = NULL;
1043 gchar *parent;
1045 if (g_file_query_exists (dir, NULL))
1047 GFileInfo *info = g_file_query_info (dir,
1048 G_FILE_ATTRIBUTE_STANDARD_TYPE,
1049 G_FILE_QUERY_INFO_NONE,
1050 NULL, NULL);
1051 if (g_file_info_get_file_type (info) != G_FILE_TYPE_DIRECTORY)
1053 g_message ("Warning: %s is a file. \n "
1054 "It is trying to be treated as a directory.",g_file_get_path (dir));
1055 g_object_unref (dir);
1056 return FALSE;
1058 g_object_unref (info);
1060 else
1062 parent = g_path_get_dirname (path);
1063 if (anjuta_util_create_dir (parent))
1065 g_free (parent);
1066 if (!g_file_make_directory (dir, NULL, &err))
1068 g_warning ("Error directory:\n %s", err->message);
1069 g_object_unref (dir);
1070 return FALSE;
1073 else
1075 g_free (parent);
1076 g_object_unref (dir);
1077 return FALSE;
1080 g_object_unref (dir);
1082 return TRUE;
1086 * anjuta_util_user_shell:
1088 * Retrieves the user's preferred shell.
1090 * Returns: A newly allocated string that is the path to the shell.
1092 /* copied from deprecated gnome_util_user_shell in libgnome */
1093 gchar *
1094 anjuta_util_user_shell (void)
1096 #ifndef G_OS_WIN32
1097 struct passwd *pw;
1098 gint i;
1099 const gchar *shell;
1100 const gchar shells [][14] = {
1101 /* Note that on some systems shells can also
1102 * be installed in /usr/bin */
1103 "/bin/bash", "/usr/bin/bash",
1104 "/bin/zsh", "/usr/bin/zsh",
1105 "/bin/tcsh", "/usr/bin/tcsh",
1106 "/bin/ksh", "/usr/bin/ksh",
1107 "/bin/csh", "/bin/sh"
1110 if (geteuid () == getuid () &&
1111 getegid () == getgid ()) {
1112 /* only in non-setuid */
1113 if ((shell = g_getenv ("SHELL"))){
1114 if (access (shell, X_OK) == 0) {
1115 return g_strdup (shell);
1119 pw = getpwuid(getuid());
1120 if (pw && pw->pw_shell) {
1121 if (access (pw->pw_shell, X_OK) == 0) {
1122 return g_strdup (pw->pw_shell);
1126 for (i = 0; i != G_N_ELEMENTS (shells); i++) {
1127 if (access (shells [i], X_OK) == 0) {
1128 return g_strdup (shells[i]);
1132 /* If /bin/sh doesn't exist, your system is truly broken. */
1133 abort ();
1135 /* Placate compiler. */
1136 return NULL;
1137 #else
1138 /* g_find_program_in_path() always looks also in the Windows
1139 * and System32 directories, so it should always find either cmd.exe
1140 * or command.com.
1142 gchar *retval = g_find_program_in_path ("cmd.exe");
1144 if (retval == NULL)
1145 retval = g_find_program_in_path ("command.com");
1147 g_assert (retval != NULL);
1149 return retval;
1150 #endif
1154 * anjuta_util_user_terminal:
1156 * Retrieves the user's preferred terminal.
1158 * Returns: (transfer full): A newly allocated strings list. The first argument
1159 * is the terminal program name. The following are the arguments needed to
1160 * execute a command. The list has to be freed with g_strfreev
1162 /* copied from deprecated gnome_execute_terminal in libgnome */
1163 gchar **
1164 anjuta_util_user_terminal (void)
1166 gchar *terminal = NULL;
1167 gchar **argv = NULL;
1168 static const gchar *terms[] = {
1169 "xdg-terminal",
1170 "gnome-terminal",
1171 "nxterm",
1172 "color-xterm",
1173 "rxvt",
1174 "xterm",
1175 "dtterm",
1176 NULL
1178 const gchar **term;
1179 GSettingsSchema *schema;
1181 schema = g_settings_schema_source_lookup (g_settings_schema_source_get_default (),
1182 "org.gnome.desktop.default-applications.terminal",
1183 TRUE);
1185 if (schema)
1187 GSettings *settings = g_settings_new ("org.gnome.desktop.default-applications.terminal");
1189 argv = g_new0 (gchar *, 3);
1190 argv[0] = g_settings_get_string (settings, "exec");
1191 argv[1] = g_settings_get_string (settings, "exec-arg");
1193 g_settings_schema_unref (schema);
1194 g_object_unref (settings);
1196 return argv;
1200 /* Search for common ones */
1201 for (term = terms; *term != NULL; term++)
1203 terminal = g_find_program_in_path (*term);
1204 if (terminal != NULL) break;
1207 /* Try xterm */
1208 g_warning (_("Cannot find a terminal; using "
1209 "xterm, even if it may not work"));
1210 terminal = g_strdup ("xterm");
1212 argv = g_new0 (char *, 3);
1213 argv[0] = terminal;
1214 /* Note that gnome-terminal takes -x and
1215 * as -e in gnome-terminal is broken we use that. */
1216 argv[1] = g_strdup (term == &terms[2] ? "-x" : "-e");
1218 return argv;
1221 static void
1222 close_pid (GPid pid,
1223 gint status,
1224 gpointer user_data)
1226 g_spawn_close_pid (pid);
1229 GPid
1230 anjuta_util_execute_shell (const gchar *dir, const gchar *command)
1232 GPid pid;
1233 gchar **argv;
1234 GError *error = NULL;
1236 g_return_val_if_fail (command != NULL, -1);
1238 argv = g_new0 (gchar *, 4);
1240 argv[0] = anjuta_util_user_shell ();
1241 #ifndef G_OS_WIN32
1242 argv[1] = g_strdup ("-c");
1243 #else
1244 argv[2] = g_strdup ("/C");
1245 #endif
1246 argv[3] = g_strdup (command);
1248 if (dir)
1249 anjuta_util_create_dir (dir);
1251 if (!g_spawn_async (dir, argv, NULL,
1252 G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
1253 NULL, NULL, &pid, &error))
1255 g_warning (_("Cannot execute command: %s (using shell %s): %s\n"),
1256 command, argv[0], error->message);
1257 pid = 0;
1260 g_child_watch_add (pid, close_pid, NULL);
1262 g_strfreev (argv);
1264 // Anjuta will take care of child exit automatically.
1265 return pid;
1268 GPid
1269 anjuta_util_execute_terminal_shell (const gchar *dir, const gchar *command)
1271 GPid pid;
1272 gchar *shell;
1273 gchar **term_argv;
1274 gchar **argv;
1275 gint i;
1276 GError *error = NULL;
1278 g_return_val_if_fail (command != NULL, -1);
1280 shell = anjuta_util_user_shell ();
1281 term_argv = anjuta_util_user_terminal ();
1282 argv = g_new0 (gchar *, g_strv_length (term_argv) + 4);
1284 i = 0;
1285 if (term_argv)
1287 for (; term_argv [i]; i++)
1288 argv[i] = term_argv[i];
1291 argv[i++] = shell;
1292 #ifndef G_OS_WIN32
1293 argv[i++] = g_strdup ("-c");
1294 #else
1295 argv[i++] = g_strdup ("/C");
1296 #endif
1297 argv[i++] = g_strdup (command);
1299 if (dir)
1300 anjuta_util_create_dir (dir);
1302 if (!g_spawn_async (dir, argv, NULL,
1303 G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
1304 NULL, NULL, &pid, &error))
1306 g_warning (_("Cannot execute command: %s (using shell %s): %s\n"),
1307 command, shell, error->message);
1308 pid = 0;
1311 g_child_watch_add (pid, close_pid, NULL);
1313 g_strfreev (argv);
1314 g_free (term_argv);
1316 // Anjuta will take care of child exit automatically.
1317 return pid;
1320 gchar *
1321 anjuta_util_convert_to_utf8 (const gchar *str)
1323 GError *error = NULL;
1324 gchar *utf8_msg_string = NULL;
1326 g_return_val_if_fail (str != NULL, NULL);
1327 g_return_val_if_fail (strlen (str) > 0, NULL);
1329 if (g_utf8_validate(str, -1, NULL))
1331 utf8_msg_string = g_strdup (str);
1333 else
1335 gsize rbytes, wbytes;
1336 utf8_msg_string = g_locale_to_utf8 (str, -1, &rbytes, &wbytes, &error);
1337 if (error != NULL) {
1338 g_warning ("g_locale_to_utf8 failed: %s\n", error->message);
1339 g_error_free (error);
1340 /* g_free (utf8_msg_string);
1341 return NULL; */
1344 return utf8_msg_string;
1347 #define LEFT_BRACE(ch) (ch == ')'? '(' : (ch == '}'? '{' : (ch == ']'? '[' : ch)))
1349 gboolean
1350 anjuta_util_jump_to_matching_brace (IAnjutaIterable *iter, gchar brace, gint limit)
1352 gchar point_ch = brace;
1353 gint cur_iteration = 0;
1354 gboolean use_limit = (limit > 0);
1355 GString *braces_stack = g_string_new ("");
1357 g_return_val_if_fail (point_ch == ')' || point_ch == ']' ||
1358 point_ch == '}', FALSE);
1360 /* DEBUG_PRINT ("%s", "Matching brace being"); */
1361 /* Push brace */
1362 g_string_prepend_c (braces_stack, point_ch);
1364 while (ianjuta_iterable_previous (iter, NULL))
1366 /* Check limit */
1367 cur_iteration++;
1368 if (use_limit && cur_iteration > limit)
1369 break;
1371 /* Skip comments and strings */
1372 IAnjutaEditorAttribute attrib =
1373 ianjuta_editor_cell_get_attribute (IANJUTA_EDITOR_CELL (iter), NULL);
1374 if (attrib == IANJUTA_EDITOR_COMMENT || attrib == IANJUTA_EDITOR_STRING)
1375 continue;
1377 /* DEBUG_PRINT ("%s", "point ch = %c", point_ch); */
1378 point_ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter), 0,
1379 NULL);
1380 if (point_ch == ')' || point_ch == ']' || point_ch == '}')
1382 /* Push brace */
1383 g_string_prepend_c (braces_stack, point_ch);
1384 continue;
1386 if (point_ch == LEFT_BRACE (braces_stack->str[0]))
1388 /* Pop brace */
1389 g_string_erase (braces_stack, 0, 1);
1391 /* Bail out if there is no more in stack */
1392 if (braces_stack->str[0] == '\0')
1394 /* DEBUG_PRINT ("%s", "Matching brace end -- found"); */
1395 return TRUE;
1398 /* DEBUG_PRINT ("%s", "Matching brace end -- not found"); */
1399 return FALSE;
1403 * anjuta_util_parse_args_from_string:
1404 * @string: arguments
1406 * Parse arguments from a string to a GList.
1408 * Returns: (element-type utf8) (transfer full): A newly allocated GList of
1409 * strings.
1411 GList*
1412 anjuta_util_parse_args_from_string (const gchar* string)
1414 gboolean escaped;
1415 gchar quote = 0;
1416 gboolean is_quote = FALSE;
1417 gchar* buffer = g_new0(gchar, strlen(string) + 1);
1418 const gchar *s;
1419 gint idx;
1420 GList* args = NULL;
1422 idx = 0;
1423 escaped = FALSE;
1424 s = string;
1426 while (*s) {
1427 if (!isspace(*s))
1428 break;
1429 s++;
1432 while (*s) {
1433 if (escaped) {
1434 /* The current char was escaped */
1435 buffer[idx++] = *s;
1436 escaped = FALSE;
1437 } else if (*s == '\\') {
1438 /* Current char is an escape */
1439 escaped = TRUE;
1440 } else if (is_quote && *s == quote) {
1441 /* Current char ends a quotation */
1442 is_quote = FALSE;
1443 if (!isspace(*(s+1)) && (*(s+1) != '\0')) {
1444 /* If there is no space after the quotation or it is not
1445 the end of the string */
1446 g_warning ("Parse error while parsing program arguments");
1448 } else if ((*s == '\"' || *s == '\'')) {
1449 if (!is_quote) {
1450 /* Current char starts a quotation */
1451 quote = *s;
1452 is_quote = TRUE;
1453 } else {
1454 /* Just a quote char inside quote */
1455 buffer[idx++] = *s;
1457 } else if (is_quote){
1458 /* Any other char inside quote */
1459 buffer[idx++] = *s;
1460 } else if (isspace(*s)) {
1461 /* Any white space outside quote */
1462 if (idx > 0) {
1463 buffer[idx++] = '\0';
1464 args = g_list_append (args, g_strdup (buffer));
1465 idx = 0;
1467 } else {
1468 buffer[idx++] = *s;
1470 s++;
1472 if (idx > 0) {
1473 /* There are chars in the buffer. Flush as the last arg */
1474 buffer[idx++] = '\0';
1475 args = g_list_append (args, g_strdup (buffer));
1476 idx = 0;
1478 if (is_quote) {
1479 g_warning ("Unclosed quotation encountered at the end of parsing");
1481 g_free (buffer);
1482 return args;
1485 gchar*
1486 anjuta_util_escape_quotes(const gchar* str)
1488 gchar *buffer;
1489 gint idx, max_size;
1490 const gchar *s = str;
1492 g_return_val_if_fail(str, NULL);
1493 idx = 0;
1495 /* We are assuming there will be less than 2048 chars to escape */
1496 max_size = strlen(str) + 2048;
1497 buffer = g_new (gchar, max_size);
1498 max_size -= 2;
1500 while(*s) {
1501 if (idx > max_size)
1502 break;
1503 if (*s == '\"' || *s == '\'' || *s == '\\')
1504 buffer[idx++] = '\\';
1505 buffer[idx++] = *s;
1506 s++;
1508 buffer[idx] = '\0';
1509 return buffer;
1512 /* Diff the text contained in uri with text. Return true if files
1513 differ, FALSE if they are identical.*/
1515 gboolean anjuta_util_diff(const gchar* uri, const gchar* text)
1517 GFile *file;
1518 GFileInfo *file_info;
1519 guint64 size;
1520 gchar* file_text = NULL;
1521 gsize bytes_read;
1523 file = g_file_new_for_uri (uri);
1524 file_info = g_file_query_info (file,
1525 G_FILE_ATTRIBUTE_STANDARD_SIZE,
1526 G_FILE_QUERY_INFO_NONE,
1527 NULL,
1528 NULL);
1530 if (file_info == NULL)
1532 g_object_unref (file);
1533 return TRUE;
1536 size = g_file_info_get_attribute_uint64(file_info,
1537 G_FILE_ATTRIBUTE_STANDARD_SIZE);
1538 g_object_unref (file_info);
1540 if (size == 0 && text == NULL)
1542 g_object_unref (file);
1543 return FALSE;
1545 else if (size == 0 || text == NULL)
1547 g_object_unref (file);
1548 return TRUE;
1551 if (!g_file_load_contents(file,
1552 NULL,
1553 &file_text,
1554 &bytes_read,
1555 NULL,
1556 NULL))
1558 g_object_unref (file);
1559 return TRUE;
1561 g_object_unref (file);
1563 if (bytes_read != size)
1565 g_free (file_text);
1566 return TRUE;
1569 /* according to g_file_load_contents's documentation
1570 * file_text is guaranteed to end with \0.
1572 if (strcmp (file_text, text) == 0)
1574 g_free (file_text);
1575 return FALSE;
1578 g_free (file_text);
1579 return TRUE;
1583 * anjuta_util_is_project_file:
1584 * @filename: the file name
1586 * Return %TRUE if the file is an anjuta project file. It is implemented by
1587 * checking only the file extension. So it does not check the existence
1588 * of the file. But it is working on an URI if it does not containt a
1589 * fragment.
1591 * Returns: %TRUE if the file is a project file, else %FALSE
1593 gboolean
1594 anjuta_util_is_project_file (const gchar *filename)
1596 gsize len = strlen (filename);
1597 return ((len > 8) && (strcmp (filename + len - 7, ".anjuta") == 0));
1601 * anjuta_util_is_template_file:
1602 * @filename: the file name
1604 * Return %TRUE if the file is an template project file. It is implemented by
1605 * checking only the file extension. So it does not check the existence
1606 * of the file. But it is working on an URI if it does not containt a
1607 * fragment.
1609 * Returns: %TRUE if the file is a template file, else %FALSE
1611 gboolean
1612 anjuta_util_is_template_file (const gchar *filename)
1614 gsize len = strlen (filename);
1615 return ((len > 9) && (strcmp (filename + len - 8, ".wiz.tgz") == 0));
1619 * anjuta_util_get_file_info_mine_type:
1620 * @info: the file information object
1622 * Return the mime type corresponding to a file infor object.
1624 * Returns: (transfer full) (allow-none): The mime type as a newly allocated
1625 * string that must be freed with g_free() or %NULL if the mime type cannot be found.
1627 gchar *
1628 anjuta_util_get_file_info_mime_type (GFileInfo *info)
1630 gchar *mime_type = NULL;
1631 const gchar *extension;
1632 const gchar *name;
1634 g_return_val_if_fail (info != NULL, NULL);
1637 /* If Anjuta is not installed in system gnome prefix, the mime types
1638 * may not have been correctly registed. In that case, we use the
1639 * following mime detection
1641 name = g_file_info_get_name (info);
1642 extension = strrchr(name, '.');
1643 if ((extension != NULL) && (extension != name))
1645 const static struct {gchar *extension; gchar *type;} anjuta_types[] = {
1646 {"anjuta", "application/x-anjuta"},
1647 {"prj", "application/x-anjuta-old"},
1648 {NULL, NULL}};
1649 gint i;
1651 for (i = 0; anjuta_types[i].extension != NULL; i++)
1653 if (strcmp(extension + 1, anjuta_types[i].extension) == 0)
1655 mime_type = g_strdup (anjuta_types[i].type);
1656 break;
1661 /* Use mime database if it is not an Anjuta type */
1662 if (mime_type == NULL)
1664 mime_type = g_content_type_get_mime_type (g_file_info_get_content_type(info));
1667 return mime_type;
1671 * anjuta_util_get_file_mine_type:
1672 * @file: the file
1674 * Check if a file exists and return its mime type.
1676 * Returns: (transfer full) (allow-none): %NULL if the corresponding file doesn't
1677 * exist or the mime type as a newly allocated string that must be freed with
1678 * g_free().
1680 gchar *
1681 anjuta_util_get_file_mime_type (GFile *file)
1683 GFileInfo *info;
1684 gchar *mime_type = NULL;
1686 g_return_val_if_fail (file != NULL, NULL);
1688 /* Get file information, check that the file exist at the same time */
1689 info = g_file_query_info (file,
1690 G_FILE_ATTRIBUTE_STANDARD_NAME ","
1691 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
1692 G_FILE_QUERY_INFO_NONE,
1693 NULL,
1694 NULL);
1696 if (info != NULL)
1698 mime_type = anjuta_util_get_file_info_mime_type (info);
1699 g_object_unref (info);
1702 return mime_type;
1705 gchar *
1706 anjuta_util_get_local_path_from_uri (const gchar *uri)
1708 GFile *file;
1709 gchar *local_path;
1711 file = g_file_new_for_uri (uri);
1712 local_path = g_file_get_path (file);
1713 g_object_unref (file);
1715 return local_path;
1718 #ifdef EMULATE_FORKPTY
1719 #include <grp.h>
1721 static int ptym_open (char *pts_name);
1722 static int ptys_open (int fdm, char * pts_name);
1725 login_tty(int ttyfd)
1727 int fd;
1728 char *fdname;
1730 #ifdef HAVE_SETSID
1731 setsid();
1732 #endif
1733 #ifdef HAVE_SETPGID
1734 setpgid(0, 0);
1735 #endif
1737 /* First disconnect from the old controlling tty. */
1738 #ifdef TIOCNOTTY
1739 fd = open("/dev/tty", O_RDWR|O_NOCTTY);
1740 if (fd >= 0)
1742 ioctl(fd, TIOCNOTTY, NULL);
1743 close(fd);
1745 else
1746 //syslog(LOG_WARNING, "NO CTTY");
1747 #endif /* TIOCNOTTY */
1749 /* Verify that we are successfully disconnected from the controlling tty. */
1750 fd = open("/dev/tty", O_RDWR|O_NOCTTY);
1751 if (fd >= 0)
1753 //syslog(LOG_WARNING, "Failed to disconnect from controlling tty.");
1754 close(fd);
1757 /* Make it our controlling tty. */
1758 #ifdef TIOCSCTTY
1759 ioctl(ttyfd, TIOCSCTTY, NULL);
1760 #endif /* TIOCSCTTY */
1762 fdname = ttyname (ttyfd);
1763 fd = open(fdname, O_RDWR);
1764 if (fd < 0)
1765 ;//syslog(LOG_WARNING, "open %s: %s", fdname, strerror(errno));
1766 else
1767 close(fd);
1769 /* Verify that we now have a controlling tty. */
1770 fd = open("/dev/tty", O_WRONLY);
1771 if (fd < 0)
1773 //syslog(LOG_WARNING, "open /dev/tty: %s", strerror(errno));
1774 return 1;
1777 close(fd);
1778 #if defined(HAVE_VHANGUP) && !defined(HAVE_REVOKE)
1780 RETSIGTYPE (*sig)();
1781 sig = signal(SIGHUP, SIG_IGN);
1782 vhangup();
1783 signal(SIGHUP, sig);
1785 #endif
1786 fd = open(fdname, O_RDWR);
1787 if (fd == -1)
1789 //syslog(LOG_ERR, "can't reopen ctty %s: %s", fdname, strerror(errno));
1790 return -1;
1793 close(ttyfd);
1795 if (fd != 0)
1796 close(0);
1797 if (fd != 1)
1798 close(1);
1799 if (fd != 2)
1800 close(2);
1802 dup2(fd, 0);
1803 dup2(fd, 1);
1804 dup2(fd, 2);
1805 if (fd > 2)
1806 close(fd);
1807 return 0;
1811 openpty(int *amaster, int *aslave, char *name, struct termios *termp,
1812 struct winsize *winp)
1814 char line[20];
1815 *amaster = ptym_open(line);
1816 if (*amaster < 0)
1817 return -1;
1818 *aslave = ptys_open(*amaster, line);
1819 if (*aslave < 0) {
1820 close(*amaster);
1821 return -1;
1823 if (name)
1824 strcpy(name, line);
1825 #ifndef TCSAFLUSH
1826 #define TCSAFLUSH TCSETAF
1827 #endif
1828 if (termp)
1829 (void) tcsetattr(*aslave, TCSAFLUSH, termp);
1830 #ifdef TIOCSWINSZ
1831 if (winp)
1832 (void) ioctl(*aslave, TIOCSWINSZ, (char *)winp);
1833 #endif
1834 return 0;
1837 static int
1838 ptym_open(char * pts_name)
1840 int fdm;
1841 #ifdef HAVE_PTSNAME
1842 char *ptr;
1844 strcpy(pts_name, "/dev/ptmx");
1845 fdm = open(pts_name, O_RDWR);
1846 if (fdm < 0)
1847 return -1;
1848 if (grantpt(fdm) < 0) { /* grant access to slave */
1849 close(fdm);
1850 return -2;
1852 if (unlockpt(fdm) < 0) { /* clear slave's lock flag */
1853 close(fdm);
1854 return -3;
1856 ptr = ptsname(fdm);
1857 if (ptr == NULL) { /* get slave's name */
1858 close (fdm);
1859 return -4;
1861 strcpy(pts_name, ptr); /* return name of slave */
1862 return fdm; /* return fd of master */
1863 #else
1864 char *ptr1, *ptr2;
1866 strcpy(pts_name, "/dev/ptyXY");
1867 /* array index: 012345689 (for references in following code) */
1868 for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1 != 0; ptr1++) {
1869 pts_name[8] = *ptr1;
1870 for (ptr2 = "0123456789abcdef"; *ptr2 != 0; ptr2++) {
1871 pts_name[9] = *ptr2;
1872 /* try to open master */
1873 fdm = open(pts_name, O_RDWR);
1874 if (fdm < 0) {
1875 if (errno == ENOENT) /* different from EIO */
1876 return -1; /* out of pty devices */
1877 else
1878 continue; /* try next pty device */
1880 pts_name[5] = 't'; /* chage "pty" to "tty" */
1881 return fdm; /* got it, return fd of master */
1884 return -1; /* out of pty devices */
1885 #endif
1888 static int
1889 ptys_open(int fdm, char * pts_name)
1891 int fds;
1892 #ifdef HAVE_PTSNAME
1893 /* following should allocate controlling terminal */
1894 fds = open(pts_name, O_RDWR);
1895 if (fds < 0) {
1896 close(fdm);
1897 return -5;
1899 if (ioctl(fds, I_PUSH, "ptem") < 0) {
1900 close(fdm);
1901 close(fds);
1902 return -6;
1904 if (ioctl(fds, I_PUSH, "ldterm") < 0) {
1905 close(fdm);
1906 close(fds);
1907 return -7;
1909 if (ioctl(fds, I_PUSH, "ttcompat") < 0) {
1910 close(fdm);
1911 close(fds);
1912 return -8;
1915 if (ioctl(fdm, I_PUSH, "pckt") < 0) {
1916 close(fdm);
1917 close(fds);
1918 return -8;
1921 if (ioctl(fdm, I_SRDOPT, RMSGN|RPROTDAT) < 0) {
1922 close(fdm);
1923 close(fds);
1924 return -8;
1927 return fds;
1928 #else
1929 int gid;
1930 struct group *grptr;
1932 grptr = getgrnam("tty");
1933 if (grptr != NULL)
1934 gid = grptr->gr_gid;
1935 else
1936 gid = -1; /* group tty is not in the group file */
1937 /* following two functions don't work unless we're root */
1938 chown(pts_name, getuid(), gid);
1939 chmod(pts_name, S_IRUSR | S_IWUSR | S_IWGRP);
1940 fds = open(pts_name, O_RDWR);
1941 if (fds < 0) {
1942 close(fdm);
1943 return -1;
1945 return fds;
1946 #endif
1950 forkpty(int *amaster, char *name, struct termios *termp, struct winsize *winp)
1952 int master, slave, pid;
1954 if (openpty(&master, &slave, name, termp, winp) == -1)
1955 return (-1);
1956 switch (pid = fork()) {
1957 case -1:
1958 return (-1);
1959 case 0:
1961 * child
1963 close(master);
1964 login_tty(slave);
1965 return (0);
1968 * parent
1970 *amaster = master;
1971 close(slave);
1972 return (pid);
1975 int scandir(const char *dir, struct dirent ***namelist,
1976 int (*select)(const struct dirent *),
1977 int (*compar)(const struct dirent **, const struct dirent **))
1979 DIR *d;
1980 struct dirent *entry;
1981 register int i=0;
1982 size_t entrysize;
1984 if ((d=opendir(dir)) == NULL)
1985 return(-1);
1987 *namelist=NULL;
1988 while ((entry=readdir(d)) != NULL)
1990 if (select == NULL || (select != NULL && (*select)(entry)))
1992 *namelist=(struct dirent **)realloc((void *)(*namelist),
1993 (size_t)((i+1)*sizeof(struct dirent *)));
1994 if (*namelist == NULL) return(-1);
1995 entrysize=sizeof(struct dirent)-sizeof(entry->d_name)+strlen(entry->d_name)+1;
1996 (*namelist)[i]=(struct dirent *)malloc(entrysize);
1997 if ((*namelist)[i] == NULL) return(-1);
1998 memcpy((*namelist)[i], entry, entrysize);
1999 i++;
2002 if (closedir(d)) return(-1);
2003 if (i == 0) return(-1);
2004 if (compar != NULL)
2005 qsort((void *)(*namelist), (size_t)i, sizeof(struct dirent *), compar);
2007 return(i);
2010 #endif /* EMULATE_FORKPTY */
2012 void
2013 anjuta_util_help_display (GtkWidget *parent,
2014 const gchar *doc_id,
2015 const gchar *item)
2017 GError *error = NULL;
2018 gchar *command;
2021 command = g_strdup_printf ("yelp help:%s%s%s",
2022 doc_id,
2023 item == NULL ? "" : "/",
2024 item == NULL ? "" : item);
2026 if (!g_spawn_command_line_async (command, &error) &&
2027 (error != NULL))
2029 g_warning ("Error executing help application: %s",
2030 error->message);
2031 g_error_free (error);
2033 g_free (command);
2037 /* The following functions are taken from gedit */
2039 /* Note that this function replace home dir with ~ */
2040 gchar *
2041 anjuta_util_uri_get_dirname (const gchar *uri)
2043 gchar *res;
2044 gchar *str;
2046 // CHECK: does it work with uri chaining? - Paolo
2047 str = g_path_get_dirname (uri);
2048 g_return_val_if_fail (str != NULL, ".");
2050 if ((strlen (str) == 1) && (*str == '.'))
2052 g_free (str);
2054 return NULL;
2057 res = anjuta_util_replace_home_dir_with_tilde (str);
2059 g_free (str);
2061 return res;
2064 gchar*
2065 anjuta_util_replace_home_dir_with_tilde (const gchar *uri)
2067 gchar *tmp;
2068 gchar *home;
2070 g_return_val_if_fail (uri != NULL, NULL);
2072 /* Note that g_get_home_dir returns a const string */
2073 tmp = (gchar *)g_get_home_dir ();
2075 if (tmp == NULL)
2076 return g_strdup (uri);
2078 home = g_filename_to_utf8 (tmp, -1, NULL, NULL, NULL);
2079 if (home == NULL)
2080 return g_strdup (uri);
2082 if (strcmp (uri, home) == 0)
2084 g_free (home);
2086 return g_strdup ("~");
2089 tmp = home;
2090 home = g_strdup_printf ("%s/", tmp);
2091 g_free (tmp);
2093 if (g_str_has_prefix (uri, home))
2095 gchar *res;
2097 res = g_strdup_printf ("~/%s", uri + strlen (home));
2099 g_free (home);
2101 return res;
2104 g_free (home);
2106 return g_strdup (uri);
2110 * anjuta_util_shell_expand:
2111 * @string: input string
2113 * Expand environment variables $(var_name) and tilde (~) in the input string.
2115 * Returns: (transfer full): a newly-allocated string that must be freed with g_free().
2117 gchar*
2118 anjuta_util_shell_expand (const gchar *string)
2120 GString* expand;
2122 if (string == NULL) return NULL;
2124 expand = g_string_sized_new (strlen (string));
2126 for (; *string != '\0'; string++)
2128 switch (*string)
2130 case '$':
2132 /* Variable expansion */
2133 const gchar *end;
2134 gint var_name_len;
2136 end = string + 1;
2137 while (isalnum (*end) || (*end == '_')) end++;
2138 var_name_len = end - string - 1;
2139 if (var_name_len > 0)
2141 const gchar *value;
2143 g_string_append_len (expand, string + 1, var_name_len);
2144 value = g_getenv (expand->str + expand->len - var_name_len);
2145 g_string_truncate (expand, expand->len - var_name_len);
2146 g_string_append (expand, value);
2147 string = end - 1;
2148 continue;
2150 break;
2152 case '~':
2154 /* User home directory expansion */
2155 if (isspace(string[1]) || (string[1] == G_DIR_SEPARATOR) || (string[1] == '\0'))
2157 g_string_append (expand, g_get_home_dir());
2158 continue;
2160 break;
2162 default:
2163 break;
2165 g_string_append_c (expand, *string);
2168 return g_string_free (expand, FALSE);
2171 gchar *
2172 anjuta_util_str_middle_truncate (const gchar *string,
2173 guint truncate_length)
2175 GString *truncated;
2176 guint length;
2177 guint n_chars;
2178 guint num_left_chars;
2179 guint right_offset;
2180 guint delimiter_length;
2181 const gchar *delimiter = "\342\200\246";
2183 g_return_val_if_fail (string != NULL, NULL);
2185 length = strlen (string);
2187 g_return_val_if_fail (g_utf8_validate (string, length, NULL), NULL);
2189 /* It doesnt make sense to truncate strings to less than
2190 * the size of the delimiter plus 2 characters (one on each
2191 * side)
2193 delimiter_length = g_utf8_strlen (delimiter, -1);
2194 if (truncate_length < (delimiter_length + 2)) {
2195 return g_strdup (string);
2198 n_chars = g_utf8_strlen (string, length);
2200 /* Make sure the string is not already small enough. */
2201 if (n_chars <= truncate_length) {
2202 return g_strdup (string);
2205 /* Find the 'middle' where the truncation will occur. */
2206 num_left_chars = (truncate_length - delimiter_length) / 2;
2207 right_offset = n_chars - truncate_length + num_left_chars + delimiter_length;
2209 truncated = g_string_new_len (string,
2210 g_utf8_offset_to_pointer (string, num_left_chars) - string);
2211 g_string_append (truncated, delimiter);
2212 g_string_append (truncated, g_utf8_offset_to_pointer (string, right_offset));
2214 return g_string_free (truncated, FALSE);
2218 * Functions to implement XDG Base Directory Specification
2219 * http://standards.freedesktop.org/basedir-spec/latest/index.html
2220 * Use this to save any config/cache/data files
2224 void
2225 anjuta_util_set_anjuta_prefix (const gchar *prefix)
2227 anjuta_prefix = g_strdup (prefix);
2230 static gchar*
2231 anjuta_util_construct_pathv (const gchar* str, va_list str_list)
2233 GPtrArray *str_arr;
2234 const gchar* tmp_str;
2235 gchar* path;
2237 str_arr = g_ptr_array_new();
2238 g_ptr_array_add (str_arr, (gpointer) str);
2240 /* Extract elements from va_list */
2241 if (str != NULL)
2243 while ((tmp_str = va_arg (str_list, const gchar*)) != NULL)
2245 g_ptr_array_add (str_arr, (gpointer)tmp_str);
2247 va_end (str_list);
2250 /* Terminate the list */
2251 g_ptr_array_add (str_arr, NULL);
2253 path = g_build_filenamev ((gchar **)str_arr->pdata);
2254 g_ptr_array_free (str_arr, TRUE);
2256 return path;
2259 static GFile*
2260 anjuta_util_get_user_cache_filev (const gchar* path, va_list list)
2262 gchar *uri_str, *base_path, *dir;
2263 GFile *uri;
2264 base_path = g_build_filename (g_get_user_cache_dir(), anjuta_prefix, path, NULL);
2266 uri_str = anjuta_util_construct_pathv (base_path, list);
2267 g_free (base_path);
2269 uri = g_file_new_for_path (uri_str);
2270 dir = g_path_get_dirname (uri_str);
2271 g_free(uri_str);
2272 if (!anjuta_util_create_dir (dir)) return NULL;
2274 return uri;
2277 GFile*
2278 anjuta_util_get_user_cache_file (const gchar* path, ...)
2280 va_list list;
2281 va_start (list, path);
2282 return anjuta_util_get_user_cache_filev (path, list);
2285 static GFile*
2286 anjuta_util_get_user_config_filev (const gchar* path, va_list list)
2288 gchar *uri_str, *base_path, *dir;
2289 GFile *uri;
2290 base_path = g_build_filename (g_get_user_config_dir(), anjuta_prefix, path, NULL);
2292 uri_str = anjuta_util_construct_pathv (base_path, list);
2293 g_free (base_path);
2295 uri = g_file_new_for_path (uri_str);
2296 dir = g_path_get_dirname (uri_str);
2297 g_free(uri_str);
2298 if (!anjuta_util_create_dir (dir)) return NULL;
2300 return uri;
2303 GFile*
2304 anjuta_util_get_user_config_file (const gchar* path, ...)
2306 va_list list;
2307 va_start (list, path);
2308 return anjuta_util_get_user_config_filev (path, list);
2311 static GFile*
2312 anjuta_util_get_user_data_filev (const gchar* path, va_list list)
2314 gchar *uri_str, *base_path, *dir;
2315 GFile *uri;
2316 base_path = g_build_filename (g_get_user_data_dir(), anjuta_prefix, path, NULL);
2318 uri_str = anjuta_util_construct_pathv (base_path, list);
2319 g_free (base_path);
2321 uri = g_file_new_for_path (uri_str);
2322 dir = g_path_get_dirname (uri_str);
2323 g_free(uri_str);
2324 if (!anjuta_util_create_dir (dir)) return NULL;
2326 return uri;
2329 GFile*
2330 anjuta_util_get_user_data_file (const gchar* path, ...)
2332 va_list list;
2333 va_start (list, path);
2334 return anjuta_util_get_user_data_filev (path, list);
2337 gchar*
2338 anjuta_util_get_user_cache_file_path (const gchar* path, ...)
2340 va_list list;
2341 GFile *file;
2342 gchar *file_path;
2343 va_start (list, path);
2344 file = anjuta_util_get_user_cache_filev (path, list);
2345 file_path = g_file_get_path (file);
2346 g_object_unref (file);
2348 return file_path;
2351 gchar*
2352 anjuta_util_get_user_config_file_path (const gchar* path, ...)
2354 va_list list;
2355 GFile *file;
2356 gchar *file_path;
2357 va_start (list, path);
2358 file = anjuta_util_get_user_config_filev (path, list);
2359 file_path = g_file_get_path (file);
2360 g_object_unref (file);
2362 return file_path;
2365 gchar*
2366 anjuta_util_get_user_data_file_path (const gchar* path, ...)
2368 va_list list;
2369 GFile *file;
2370 gchar *file_path;;
2371 va_start (list, path);
2372 file = anjuta_util_get_user_data_filev (path, list);
2373 file_path = g_file_get_path (file);
2374 g_object_unref (file);
2376 return file_path;
2379 GList *
2380 anjuta_util_convert_gfile_list_to_path_list (GList *list)
2382 GList *path_list;
2383 GList *current_file;
2384 gchar *path;
2386 path_list = NULL;
2388 for (current_file = list; current_file != NULL; current_file = g_list_next (current_file))
2390 path = g_file_get_path (current_file->data);
2392 /* Ignore files with invalid paths */
2393 if (path)
2394 path_list = g_list_append (path_list, path);
2397 return path_list;
2400 GList *
2401 anjuta_util_convert_gfile_list_to_relative_path_list (GList *list,
2402 const gchar *parent)
2404 GFile *parent_file;
2405 GList *path_list;
2406 GList *current_file;
2407 gchar *path;
2409 parent_file = g_file_new_for_path (parent);
2410 path_list = NULL;
2412 if (parent_file)
2414 for (current_file = list; current_file != NULL; current_file = g_list_next (current_file))
2416 path = g_file_get_relative_path (parent_file, current_file->data);
2418 /* Ignore files with invalid paths */
2419 if (path)
2420 path_list = g_list_append (path_list, path);
2423 g_object_unref (parent_file);
2426 return path_list;
2431 * anjuta_util_builder_new:
2432 * @filename: Builder file name to open
2433 * @error: Optional error object, if %NULL display a dialog if the file is missing
2435 * Create a new GtkBuilder object and load the file in it. Display an error
2436 * if the file is missing. Use a dialog if error is %NULL, just a warning
2437 * if the error can be reported.
2439 * Returns: The new GtkBuilder object
2441 GtkBuilder *
2442 anjuta_util_builder_new (const gchar *filename, GError **error)
2444 GtkBuilder *bxml = gtk_builder_new ();
2445 GError *err = NULL;
2447 /* Load glade file */
2448 if (!gtk_builder_add_from_file (bxml, filename, &err))
2450 g_object_unref (bxml);
2451 bxml = NULL;
2453 /* Display the error to the user if it cannot be reported to the caller */
2454 if (error == NULL)
2456 anjuta_util_dialog_error (NULL, _("Unable to load user interface file: %s"), err->message);
2458 else
2460 g_warning ("Couldn't load builder file: %s", err->message);
2462 g_propagate_error (error, err);
2465 /* Tag the builder object with the filename to allow better error message
2466 * with the following function */
2467 if (bxml != NULL)
2469 g_object_set_data_full (G_OBJECT (bxml), "filename", g_strdup (filename), g_free);
2472 return bxml;
2476 * anjuta_util_builder_get_objects:
2477 * @builder: Builder object
2478 * @first_widget: Name of first widget to get
2479 * ...: Address to store the first widget pointer, followed optionally by
2480 * more name/pointer pairs, followed by %NULL
2482 * Create a new GtkBuilder object and load the file in it. Display an error
2483 * if the file is missing. Use a dialog if error is %NULL, just a warning
2484 * if the error can be reported.
2486 * Returns: %TRUE is everything works as expected.
2488 gboolean
2489 anjuta_util_builder_get_objects (GtkBuilder *builder, const gchar *first_widget,...)
2491 va_list args;
2492 const gchar *name;
2493 GObject **object_ptr;
2494 gboolean missing = FALSE;
2496 va_start (args, first_widget);
2498 for (name = first_widget; name; name = va_arg (args, char *))
2500 object_ptr = va_arg (args, void *);
2501 *object_ptr = gtk_builder_get_object (builder, name);
2503 /* Object not found, display a warning */
2504 if (!*object_ptr)
2506 const gchar *filename = (const gchar *)g_object_get_data (G_OBJECT (builder), "filename");
2507 if (filename)
2509 g_warning ("Missing widget '%s' in file %s", name, filename);
2511 else
2513 g_warning("Missing widget '%s'", name);
2515 missing = TRUE;
2518 va_end (args);
2520 return !missing;
2524 * anjuta_utils_drop_get_files:
2525 * @selection_data: the #GtkSelectionData from drag_data_received
2527 * Create a list of valid uri's from a uri-list drop.
2529 * Return value: (element-type GFile*): a list of GFiles
2531 GSList*
2532 anjuta_utils_drop_get_files (GtkSelectionData *selection_data)
2534 gchar **uris;
2535 gint i;
2536 GSList* files = NULL;
2538 uris = g_uri_list_extract_uris ((gchar *) gtk_selection_data_get_data (selection_data));
2540 for (i = 0; uris[i] != NULL; i++)
2542 GFile* file = g_file_new_for_uri (uris[i]);
2543 files = g_slist_append(files, file);
2546 return files;
2550 * anjuta_util_get_user_mail:
2552 * Returns: The e-mail Address of the logged-in user. The resulting string
2553 * must be free'd after use.
2555 gchar*
2556 anjuta_util_get_user_mail()
2558 /* FIXME: Use libfolks or something like it to query the mail address */
2559 return g_strconcat(g_get_user_name (), "@", g_get_host_name (), NULL);
2563 * anjuta_utils_clone_string_gptrarray:
2564 * @source: The source GPtrArray containing items representing strings
2566 * Clones the contents of source GPtrArray into a new allocated GPtrArray.
2568 * Return a new allocated GPtrArray with strings g_strdup (), %NULL on error.
2569 * The returned array has set g_free as GDestroyNotity function, so that user
2570 * should only care to g_ptr_array_unref () without freeing the strings.
2572 GPtrArray *
2573 anjuta_util_clone_string_gptrarray (const GPtrArray* source)
2575 gint i;
2576 GPtrArray *dest;
2578 g_return_val_if_fail (source != NULL, NULL);
2580 dest = g_ptr_array_sized_new (source->len);
2581 g_ptr_array_set_free_func (dest, g_free);
2583 for (i = 0; i < source->len; i++)
2585 g_ptr_array_add (dest, g_strdup (g_ptr_array_index (source, i)));
2588 return dest;
2591 void
2592 anjuta_util_list_all_dir_children (GList **children, GFile *dir)
2594 GFileEnumerator *list;
2596 list = g_file_enumerate_children (dir,
2597 G_FILE_ATTRIBUTE_STANDARD_NAME,
2598 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
2599 NULL,
2600 NULL);
2602 if (list != NULL)
2604 GFileInfo *info;
2606 while ((info = g_file_enumerator_next_file (list, NULL, NULL)) != NULL)
2608 const gchar *name;
2609 GFile *file;
2611 name = g_file_info_get_name (info);
2612 file = g_file_get_child (dir, name);
2613 g_object_unref (info);
2615 if (g_file_query_file_type (file, G_FILE_QUERY_INFO_NONE, NULL) == G_FILE_TYPE_DIRECTORY)
2617 anjuta_util_list_all_dir_children (children, file);
2618 g_object_unref (file);
2620 else
2622 *children = g_list_prepend (*children, file);
2625 g_file_enumerator_close (list, NULL, NULL);
2626 g_object_unref (list);
2630 GPtrArray *
2631 anjuta_util_convert_string_list_to_array (GList *list)
2633 GList *node;
2634 GPtrArray *res;
2636 g_return_val_if_fail (list != NULL, NULL);
2638 res = g_ptr_array_new_with_free_func (g_free);
2640 node = list;
2641 while (node != NULL)
2643 g_ptr_array_add (res, g_strdup (node->data));
2645 node = g_list_next (node);
2648 return res;