Updated Spanish translation
[anjuta.git] / libanjuta / anjuta-utils.c
blob9f208656cd489d22ff7a9ba08187720527d0acc2
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 /* Common preferences */
68 #define ANJUTA_PREF_SCHEMA "org.gnome.anjuta"
70 #define LAST_EMAIL "email"
73 static gchar *anjuta_prefix = "anjuta";
75 static void
76 anjuta_util_from_file_to_file (GInputStream *istream,
77 GOutputStream *ostream)
79 gsize bytes = 1;
80 GError *error = NULL;
81 gchar buffer[FILE_BUFFER_SIZE];
83 while (bytes != 0 && bytes != -1)
85 bytes = g_input_stream_read (istream, buffer,
86 sizeof (buffer),
87 NULL, &error);
88 if (error)
89 break;
91 g_output_stream_write (ostream, buffer,
92 bytes,
93 NULL, &error);
94 if (error)
95 break;
98 if (error)
100 g_warning ("%s", error->message);
101 g_error_free (error);
102 error = NULL;
105 if (!g_output_stream_close (ostream, NULL, &error))
107 g_warning ("%s", error->message);
108 g_error_free (error);
109 error = NULL;
111 if (!g_input_stream_close (istream, NULL, &error))
113 g_warning ("%s", error->message);
114 g_error_free (error);
119 * anjuta_util_copy_file:
120 * @src: the file where copy
121 * @dest: the path to copy the @src
122 * @show_error: %TRUE to show a dialog error
124 * Copies @src to @dest and shows a dialog error in case is needed.
126 * Returns: %TRUE if there was an error copying the file.
128 gboolean
129 anjuta_util_copy_file (const gchar * src, const gchar * dest, gboolean show_error)
131 GFile *src_file, *dest_file;
132 GFileInputStream *istream;
133 GFileOutputStream *ostream;
134 GError *error = NULL;
135 gboolean toret = FALSE;
137 src_file = g_file_new_for_path (src);
138 dest_file = g_file_new_for_path (dest);
140 istream = g_file_read (src_file, NULL, &error);
141 if (error)
142 goto free;
144 ostream = g_file_create (dest_file, G_FILE_CREATE_NONE,
145 NULL, &error);
146 if (error)
147 goto free;
149 anjuta_util_from_file_to_file (G_INPUT_STREAM (istream), G_OUTPUT_STREAM (ostream));
151 free: if (error)
153 if (show_error)
154 anjuta_util_dialog_error_system (NULL, error->code,
155 error->message);
157 g_warning ("%s", error->message);
159 toret = TRUE;
162 g_object_unref (src_file);
163 g_object_unref (dest_file);
165 return toret;
168 void
169 anjuta_util_color_from_string (const gchar * val, guint16 * r, guint16 * g, guint16 * b)
171 GdkColor color;
172 if (gdk_color_parse(val, &color))
174 *r = color.red;
175 *g = color.green;
176 *b =color.blue;
180 gchar *
181 anjuta_util_string_from_color (guint16 r, guint16 g, guint16 b)
183 return g_strdup_printf("#%02x%02x%02x", r >> 8, g >> 8, b >> 8);
186 GtkWidget*
187 anjuta_util_button_new_with_stock_image (const gchar* text,
188 const gchar* stock_id)
190 GtkWidget *button;
191 GtkWidget *child;
192 GtkStockItem item;
193 GtkWidget *label;
194 GtkWidget *image;
195 GtkWidget *hbox;
196 GtkWidget *align;
198 button = gtk_button_new ();
200 child = gtk_bin_get_child (GTK_BIN (button));
201 if (child)
202 gtk_container_remove (GTK_CONTAINER (button), child);
204 if (gtk_stock_lookup (stock_id, &item))
206 label = gtk_label_new_with_mnemonic (text);
208 gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
210 image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON);
211 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 2);
213 align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
215 gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
216 gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
218 gtk_container_add (GTK_CONTAINER (button), align);
219 gtk_container_add (GTK_CONTAINER (align), hbox);
220 gtk_widget_show_all (align);
222 return button;
225 label = gtk_label_new_with_mnemonic (text);
226 gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
228 gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
230 gtk_widget_show (label);
231 gtk_container_add (GTK_CONTAINER (button), label);
233 return button;
236 GtkWidget*
237 anjuta_util_dialog_add_button (GtkDialog *dialog, const gchar* text,
238 const gchar* stock_id, gint response_id)
240 GtkWidget *button;
242 g_return_val_if_fail (GTK_IS_DIALOG (dialog), NULL);
243 g_return_val_if_fail (text != NULL, NULL);
244 g_return_val_if_fail (stock_id != NULL, NULL);
246 button = anjuta_util_button_new_with_stock_image (text, stock_id);
247 g_return_val_if_fail (button != NULL, NULL);
249 gtk_widget_set_can_default (button, TRUE);
251 gtk_widget_show (button);
253 gtk_dialog_add_action_widget (dialog, button, response_id);
255 return button;
258 void
259 anjuta_util_dialog_error (GtkWindow *parent, const gchar *mesg, ...)
261 gchar* message;
262 va_list args;
263 GtkWidget *dialog;
264 GtkWindow *real_parent;
266 va_start (args, mesg);
267 message = g_strdup_vprintf (mesg, args);
268 va_end (args);
270 if (parent && GTK_IS_WINDOW (parent))
272 real_parent = parent;
274 else
276 real_parent = NULL;
279 // Dialog to be HIG compliant
280 dialog = gtk_message_dialog_new (real_parent,
281 GTK_DIALOG_DESTROY_WITH_PARENT,
282 GTK_MESSAGE_ERROR,
283 GTK_BUTTONS_CLOSE, "%s", message);
284 g_signal_connect (G_OBJECT (dialog), "response",
285 G_CALLBACK (gtk_widget_destroy), NULL);
286 gtk_widget_show (dialog);
287 g_free (message);
290 void
291 anjuta_util_dialog_warning (GtkWindow *parent, const gchar * mesg, ...)
293 gchar* message;
294 va_list args;
295 GtkWidget *dialog;
296 GtkWindow *real_parent;
298 va_start (args, mesg);
299 message = g_strdup_vprintf (mesg, args);
300 va_end (args);
302 if (parent && GTK_IS_WINDOW (parent))
304 real_parent = parent;
306 else
308 real_parent = NULL;
311 // Dialog to be HIG compliant
312 dialog = gtk_message_dialog_new (real_parent,
313 GTK_DIALOG_DESTROY_WITH_PARENT,
314 GTK_MESSAGE_WARNING,
315 GTK_BUTTONS_CLOSE, "%s", message);
316 g_signal_connect (G_OBJECT (dialog), "response",
317 G_CALLBACK (gtk_widget_destroy), NULL);
318 gtk_widget_show (dialog);
319 g_free (message);
322 void
323 anjuta_util_dialog_info (GtkWindow *parent, const gchar * mesg, ...)
325 gchar* message;
326 va_list args;
327 GtkWidget *dialog;
328 GtkWindow *real_parent;
330 va_start (args, mesg);
331 message = g_strdup_vprintf (mesg, args);
332 va_end (args);
334 if (parent && GTK_IS_WINDOW (parent))
336 real_parent = parent;
338 else
340 real_parent = NULL;
342 // Dialog to be HIG compliant
343 dialog = gtk_message_dialog_new (real_parent,
344 GTK_DIALOG_DESTROY_WITH_PARENT,
345 GTK_MESSAGE_INFO,
346 GTK_BUTTONS_CLOSE, "%s", message);
347 g_signal_connect (G_OBJECT (dialog), "response",
348 G_CALLBACK (gtk_widget_destroy), NULL);
349 gtk_widget_show (dialog);
350 g_free (message);
353 void
354 anjuta_util_dialog_error_system (GtkWindow* parent, gint errnum,
355 const gchar * mesg, ... )
357 gchar* message;
358 gchar* tot_mesg;
359 va_list args;
360 GtkWidget *dialog;
361 GtkWindow *real_parent;
363 va_start (args, mesg);
364 message = g_strdup_vprintf (mesg, args);
365 va_end (args);
367 if (0 != errnum) {
368 /* Avoid space in translated string */
369 tot_mesg = g_strconcat (message, "\n", _("System:"), " ",
370 g_strerror(errnum), NULL);
371 g_free (message);
372 } else
373 tot_mesg = message;
375 if (parent && GTK_IS_WINDOW (parent))
377 real_parent = parent;
379 else
381 real_parent = NULL;
383 // Dialog to be HIG compliant
384 dialog = gtk_message_dialog_new (real_parent,
385 GTK_DIALOG_DESTROY_WITH_PARENT,
386 GTK_MESSAGE_ERROR,
387 GTK_BUTTONS_CLOSE, "%s", tot_mesg);
388 g_signal_connect (G_OBJECT (dialog), "response",
389 G_CALLBACK (gtk_widget_destroy), NULL);
390 gtk_widget_show (dialog);
391 g_free (tot_mesg);
394 gboolean
395 anjuta_util_dialog_boolean_question (GtkWindow *parent, gboolean default_to_yes,
396 const gchar *mesg, ...)
398 gchar* message;
399 va_list args;
400 GtkWidget *dialog;
401 gint ret;
402 GtkWindow *real_parent;
404 va_start (args, mesg);
405 message = g_strdup_vprintf (mesg, args);
406 va_end (args);
408 if (parent && GTK_IS_WINDOW (parent))
410 real_parent = parent;
412 else
414 real_parent = NULL;
417 dialog = gtk_message_dialog_new (real_parent,
418 GTK_DIALOG_DESTROY_WITH_PARENT,
419 GTK_MESSAGE_QUESTION,
420 GTK_BUTTONS_YES_NO, "%s", message);
421 if (default_to_yes)
422 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES);
424 ret = gtk_dialog_run (GTK_DIALOG (dialog));
425 gtk_widget_destroy (dialog);
426 g_free (message);
428 return (ret == GTK_RESPONSE_YES);
431 gboolean
432 anjuta_util_dialog_input (GtkWindow *parent, const gchar *prompt,
433 const gchar *default_value, gchar **return_value)
435 GtkWidget *dialog, *label, *frame, *entry, *dialog_vbox, *vbox;
436 gint res;
437 gchar *markup;
438 GtkWindow *real_parent;
440 if (parent && GTK_IS_WINDOW (parent))
442 real_parent = parent;
444 else
446 real_parent = NULL;
449 dialog = gtk_dialog_new_with_buttons (prompt, real_parent,
450 GTK_DIALOG_DESTROY_WITH_PARENT,
451 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
452 GTK_STOCK_OK, GTK_RESPONSE_OK,
453 NULL);
454 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
455 dialog_vbox = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
456 gtk_window_set_default_size (GTK_WINDOW (dialog), 400, -1);
457 gtk_widget_show (dialog_vbox);
459 markup = g_strconcat ("<b>", prompt, "</b>", NULL);
460 label = gtk_label_new (NULL);
461 gtk_label_set_markup (GTK_LABEL (label), markup);
462 gtk_widget_show (label);
463 g_free (markup);
465 frame = gtk_frame_new (NULL);
466 gtk_frame_set_label_widget (GTK_FRAME (frame), label);
467 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
468 gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
469 gtk_widget_show (frame);
470 gtk_box_pack_start (GTK_BOX (dialog_vbox), frame, FALSE, FALSE, 0);
472 vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
473 gtk_widget_show (vbox);
474 gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
475 gtk_container_add (GTK_CONTAINER (frame), vbox);
477 entry = gtk_entry_new ();
478 gtk_widget_show (entry);
479 gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
480 gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
481 if (default_value)
482 gtk_entry_set_text (GTK_ENTRY (entry), default_value);
484 res = gtk_dialog_run (GTK_DIALOG (dialog));
486 if (gtk_entry_get_text (GTK_ENTRY (entry)) &&
487 strlen (gtk_entry_get_text (GTK_ENTRY (entry))) > 0)
489 *return_value = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
491 else
493 *return_value = NULL;
495 gtk_widget_destroy (dialog);
496 return (res == GTK_RESPONSE_OK);
499 static void
500 on_install_files_done (GObject *proxy, GAsyncResult *result,
501 gpointer user_data)
503 GError *error = NULL;
504 g_dbus_proxy_call_finish ((GDBusProxy *) proxy, result, &error);
505 if (error)
508 Only dbus error is handled. Rest of the errors are from packagekit
509 which have already been notified to user by packagekit.
511 if (error->domain == G_DBUS_ERROR)
513 const gchar *error_message = NULL;
515 /* Service error which implies packagekit is missing */
516 if (error->code == G_DBUS_ERROR_SERVICE_UNKNOWN)
518 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.");
520 /* General dbus error implies failure to call dbus method */
521 else if (error->code != G_DBUS_ERROR_NO_REPLY)
523 error_message = error->message;
525 if (error_message)
526 anjuta_util_dialog_error (NULL,
527 _("Installation failed: %s"),
528 error_message);
530 g_error_free (error);
534 gboolean
535 anjuta_util_install_files (const gchar * const names)
537 GDBusConnection * connection;
538 GDBusProxy * proxy;
539 guint32 xid = 0;
540 gchar ** pkgv;
542 if (!names)
543 return FALSE;
545 connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
546 if (!connection)
547 return FALSE;
549 proxy = g_dbus_proxy_new_sync (connection,
550 G_DBUS_PROXY_FLAGS_NONE,
551 NULL,
552 "org.freedesktop.PackageKit",
553 "/org/freedesktop/PackageKit",
554 "org.freedesktop.PackageKit.Modify",
555 NULL,
556 NULL);
557 if (!proxy)
558 return FALSE;
560 pkgv = g_strsplit (names, ", ", 0);
561 g_dbus_proxy_call (proxy, "InstallProvideFiles",
562 g_variant_new ("(u^ass)",
563 xid,
564 pkgv,
565 ""),
566 G_DBUS_CALL_FLAGS_NONE,
568 NULL,
569 on_install_files_done,
570 NULL);
571 g_strfreev (pkgv);
572 return TRUE;
575 gboolean
576 anjuta_util_package_is_installed (const gchar * package, gboolean show)
578 const gchar* const argv[] = { "pkg-config", "--exists", package, NULL };
579 int exit_status;
580 GError *err = NULL;
582 if (!g_spawn_sync (NULL, (gchar**)argv, NULL, G_SPAWN_SEARCH_PATH, NULL,
583 NULL, NULL, NULL, &exit_status, &err))
585 if (show)
587 anjuta_util_dialog_error (NULL,
588 _("Failed to run \"%s\". "
589 "The returned error was: \"%s\"."),
590 "pkg-config --exists", err->message);
592 g_error_free (err);
596 if (g_spawn_check_exit_status (exit_status, NULL))
597 return TRUE;
599 if (show)
601 anjuta_util_dialog_error (NULL,
602 _("The \"%s\" package is not installed.\n"
603 "Please install it."), package);
606 return FALSE;
609 gboolean
610 anjuta_util_prog_is_installed (const gchar * prog, gboolean show)
612 gchar* prog_path = g_find_program_in_path (prog);
613 if (prog_path)
615 g_free (prog_path);
616 return TRUE;
618 if (show)
620 anjuta_util_dialog_error (NULL, _("The \"%s\" utility is not installed.\n"
621 "Please install it."), prog);
623 return FALSE;
626 gchar *
627 anjuta_util_get_a_tmp_file (void)
629 static gint count = 0;
630 gchar *filename;
631 const gchar *tmpdir;
633 tmpdir = g_get_tmp_dir ();
634 filename =
635 g_strdup_printf ("%s/anjuta_%d.%d", tmpdir, count++, getpid ());
636 return filename;
639 /* GList of strings operations */
640 GList *
641 anjuta_util_glist_from_string (const gchar *string)
643 gchar *str, *temp, buff[256];
644 GList *list;
645 gchar *word_start, *word_end;
647 list = NULL;
648 temp = g_strdup (string);
649 str = temp;
650 if (!str)
651 return NULL;
653 while (1)
655 gint i;
656 gchar *ptr;
658 /* Remove leading spaces */
659 while (isspace (*str) && *str != '\0')
660 str++;
661 if (*str == '\0')
662 break;
664 /* Find start and end of word */
665 word_start = str;
666 while (!isspace (*str) && *str != '\0')
667 str++;
668 word_end = str;
670 /* Copy the word into the buffer */
671 for (ptr = word_start, i = 0; ptr < word_end; ptr++, i++)
672 buff[i] = *ptr;
673 buff[i] = '\0';
674 if (strlen (buff))
675 list = g_list_append (list, g_strdup (buff));
676 if (*str == '\0')
677 break;
679 if (temp)
680 g_free (temp);
681 return list;
684 /* Prefix the strings */
685 void
686 anjuta_util_glist_strings_prefix (GList * list, const gchar *prefix)
688 GList *node;
689 node = list;
691 g_return_if_fail (prefix != NULL);
692 while (node)
694 gchar* tmp;
695 tmp = node->data;
696 node->data = g_strconcat (prefix, tmp, NULL);
697 if (tmp) g_free (tmp);
698 node = g_list_next (node);
702 /* Suffix the strings */
703 void
704 anjuta_util_glist_strings_sufix (GList * list, const gchar *sufix)
706 GList *node;
707 node = list;
709 g_return_if_fail (sufix != NULL);
710 while (node)
712 gchar* tmp;
713 tmp = node->data;
714 node->data = g_strconcat (tmp, sufix, NULL);
715 if (tmp) g_free (tmp);
716 node = g_list_next (node);
720 /* Duplicate list of strings */
721 GList*
722 anjuta_util_glist_strings_dup (GList * list)
724 GList *node;
725 GList *new_list;
727 new_list = NULL;
728 node = list;
729 while (node)
731 if (node->data)
732 new_list = g_list_append (new_list, g_strdup(node->data));
733 else
734 new_list = g_list_append (new_list, NULL);
735 node = g_list_next (node);
737 return new_list;
740 /* Join list of strings using the given delimiter */
741 gchar*
742 anjuta_util_glist_strings_join (GList * list, gchar *delimiter)
744 GString *joined;
745 gboolean first = TRUE;
746 GList *node;
748 joined = g_string_new (NULL);
749 node = list;
750 while (node)
752 if (node->data)
754 if (!first)
755 g_string_append (joined, delimiter);
756 else
757 first = FALSE;
758 g_string_append (joined, node->data);
760 node = g_list_next (node);
762 if (joined->len > 0)
763 return g_string_free (joined, FALSE);
764 else
765 g_string_free (joined, TRUE);
766 return NULL;
769 gchar*
770 anjuta_util_get_real_path (const gchar *path)
772 if (path != NULL)
774 gchar *result;
775 #ifndef G_OS_WIN32
776 # ifdef PATH_MAX
777 gchar buf[PATH_MAX+1];
779 result = realpath (path, buf);
780 if (result != NULL)
782 *(buf + PATH_MAX) = '\0'; /* ensure a terminator */
783 return g_strdup (buf);
785 # else
786 char *buf;
787 /* the string returned by realpath should be cleaned with
788 free(), not g_free() */
789 buf = realpath (path, NULL);
790 if (buf != NULL)
792 result = g_strdup (buf);
793 free (buf);
794 return result;
796 # endif
797 #else
798 char dummy;
799 int rc, len;
801 /* Get length of path */
802 rc = GetFullPathName (path, 1, &dummy, NULL);
803 if (rc == 0)
805 /* Weird failure */
806 return g_strdup (path);
809 len = rc + 1;
810 result = g_malloc (len);
812 /* Get the real path */
813 rc = GetFullPathName (path, len, result, NULL);
814 if (rc == 0 || rc > len)
816 /* Another weird failure */
817 g_free (result);
818 return g_strdup (path);
821 return result;
822 #endif
824 return NULL;
828 * anjuta_util_get_current_dir:
830 * Get current working directory, unlike g_get_current_dir, keeps symbolic links
831 * in path name.
833 * Returns: The current working directory.
835 gchar*
836 anjuta_util_get_current_dir (void)
838 const gchar *pwd;
840 pwd = g_getenv ("PWD");
841 if (pwd != NULL)
843 return g_strdup (pwd);
845 else
847 return g_get_current_dir ();
851 static gboolean
852 is_valid_scheme_character (char c)
854 return g_ascii_isalnum (c) || c == '+' || c == '-' || c == '.';
857 /* Following RFC 2396, valid schemes are built like:
858 * scheme = alpha *( alpha | digit | "+" | "-" | "." )
860 static gboolean
861 has_valid_scheme (const char *uri)
863 const char *p;
865 p = uri;
867 if (!g_ascii_isalpha (*p))
868 return FALSE;
870 do {
871 p++;
872 } while (is_valid_scheme_character (*p));
874 return *p == ':';
878 * anjuta_util_file_new_for_commandline_arg:
879 * @arg: URI or relative or absolute file path
881 * Create a new file corresponding to arg, unlike g_file_new_for_commandline_arg,
882 * keeps symbolic links in path name.
884 * Returns: (transfer full): A new GFile object
886 GFile *
887 anjuta_util_file_new_for_commandline_arg (const gchar *arg)
889 GFile *file;
890 char *filename;
891 char *current_dir;
893 g_return_val_if_fail (arg != NULL, NULL);
895 if (g_path_is_absolute (arg))
896 return g_file_new_for_path (arg);
898 if (has_valid_scheme (arg))
899 return g_file_new_for_uri (arg);
901 current_dir = anjuta_util_get_current_dir ();
902 filename = g_build_filename (current_dir, arg, NULL);
903 g_free (current_dir);
905 file = g_file_new_for_path (filename);
906 g_free (filename);
908 return file;
912 /* Dedup a list of paths - duplicates are removed from the tail.
913 ** Useful for deduping Recent Files and Recent Projects */
914 GList*
915 anjuta_util_glist_path_dedup(GList *list)
917 GList *nlist = NULL, *tmp, *tmp1;
918 gchar *path;
919 struct stat s;
920 for (tmp = list; tmp; tmp = g_list_next(tmp))
922 path = anjuta_util_get_real_path ((const gchar *) tmp->data);
923 if (path)
925 if (stat (path, &s) != 0)
927 g_free(path);
929 else
931 for (tmp1 = nlist; tmp1; tmp1 = g_list_next(tmp1))
933 if (0 == strcmp((const char *) tmp1->data, path))
935 g_free(path);
936 path = NULL;
937 break;
940 if (path)
941 nlist = g_list_prepend(nlist, path);
945 anjuta_util_glist_strings_free(list);
946 nlist = g_list_reverse(nlist);
947 return nlist;
950 static gint
951 sort_node (gchar* a, gchar *b)
953 if ( !a && !b) return 0;
954 else if (!a) return -1;
955 else if (!b) return 1;
956 return strcmp (a, b);
959 /* Sort the list alphabatically */
960 GList*
961 anjuta_util_glist_strings_sort (GList * list)
963 return g_list_sort(list, (GCompareFunc)sort_node);
966 /* Free the strings and GList */
967 void
968 anjuta_util_glist_strings_free (GList * list)
970 g_list_foreach (list, (GFunc) g_free, NULL);
971 g_list_free (list);
975 anjuta_util_type_from_string (AnjutaUtilStringMap *map, const char *str)
977 int i = 0;
979 while (-1 != map[i].type)
981 if (0 == strcmp(map[i].name, str))
982 return map[i].type;
983 ++ i;
985 return -1;
988 const char*
989 anjuta_util_string_from_type (AnjutaUtilStringMap *map, int type)
991 int i = 0;
992 while (-1 != map[i].type)
994 if (map[i].type == type)
995 return map[i].name;
996 ++ i;
998 return "";
1001 GList*
1002 anjuta_util_glist_from_map (AnjutaUtilStringMap *map)
1004 GList *out_list = NULL;
1005 int i = 0;
1006 while (-1 != map[i].type)
1008 out_list = g_list_append(out_list, map[i].name);
1009 ++ i;
1011 return out_list;
1015 GList *
1016 anjuta_util_update_string_list (GList *p_list, const gchar *p_str, gint length)
1018 gint i;
1019 gchar *str;
1020 if (!p_str)
1021 return p_list;
1022 for (i = 0; i < g_list_length (p_list); i++)
1024 str = (gchar *) g_list_nth_data (p_list, i);
1025 if (!str)
1026 continue;
1027 if (strcmp (p_str, str) == 0)
1029 p_list = g_list_remove (p_list, str);
1030 p_list = g_list_prepend (p_list, str);
1031 return p_list;
1034 p_list = g_list_prepend (p_list, g_strdup (p_str));
1035 while (g_list_length (p_list) > length)
1037 str = g_list_nth_data (p_list, g_list_length (p_list) - 1);
1038 p_list = g_list_remove (p_list, str);
1039 g_free (str);
1041 return p_list;
1044 gboolean
1045 anjuta_util_create_dir (const gchar* path)
1047 GFile *dir = g_file_new_for_path (path);
1048 GError *err = NULL;
1049 gchar *parent;
1051 if (g_file_query_exists (dir, NULL))
1053 GFileInfo *info = g_file_query_info (dir,
1054 G_FILE_ATTRIBUTE_STANDARD_TYPE,
1055 G_FILE_QUERY_INFO_NONE,
1056 NULL, NULL);
1057 if (g_file_info_get_file_type (info) != G_FILE_TYPE_DIRECTORY)
1059 g_message ("Warning: %s is a file. \n "
1060 "It is trying to be treated as a directory.",g_file_get_path (dir));
1061 g_object_unref (dir);
1062 return FALSE;
1064 g_object_unref (info);
1066 else
1068 parent = g_path_get_dirname (path);
1069 if (anjuta_util_create_dir (parent))
1071 g_free (parent);
1072 if (!g_file_make_directory (dir, NULL, &err))
1074 g_warning ("Error directory:\n %s", err->message);
1075 g_object_unref (dir);
1076 return FALSE;
1079 else
1081 g_free (parent);
1082 g_object_unref (dir);
1083 return FALSE;
1086 g_object_unref (dir);
1088 return TRUE;
1092 * anjuta_util_user_shell:
1094 * Retrieves the user's preferred shell.
1096 * Returns: A newly allocated string that is the path to the shell.
1098 /* copied from deprecated gnome_util_user_shell in libgnome */
1099 gchar *
1100 anjuta_util_user_shell (void)
1102 #ifndef G_OS_WIN32
1103 struct passwd *pw;
1104 gint i;
1105 const gchar *shell;
1106 const gchar shells [][14] = {
1107 /* Note that on some systems shells can also
1108 * be installed in /usr/bin */
1109 "/bin/bash", "/usr/bin/bash",
1110 "/bin/zsh", "/usr/bin/zsh",
1111 "/bin/tcsh", "/usr/bin/tcsh",
1112 "/bin/ksh", "/usr/bin/ksh",
1113 "/bin/csh", "/bin/sh"
1116 if (geteuid () == getuid () &&
1117 getegid () == getgid ()) {
1118 /* only in non-setuid */
1119 if ((shell = g_getenv ("SHELL"))){
1120 if (access (shell, X_OK) == 0) {
1121 return g_strdup (shell);
1125 pw = getpwuid(getuid());
1126 if (pw && pw->pw_shell) {
1127 if (access (pw->pw_shell, X_OK) == 0) {
1128 return g_strdup (pw->pw_shell);
1132 for (i = 0; i != G_N_ELEMENTS (shells); i++) {
1133 if (access (shells [i], X_OK) == 0) {
1134 return g_strdup (shells[i]);
1138 /* If /bin/sh doesn't exist, your system is truly broken. */
1139 abort ();
1141 /* Placate compiler. */
1142 return NULL;
1143 #else
1144 /* g_find_program_in_path() always looks also in the Windows
1145 * and System32 directories, so it should always find either cmd.exe
1146 * or command.com.
1148 gchar *retval = g_find_program_in_path ("cmd.exe");
1150 if (retval == NULL)
1151 retval = g_find_program_in_path ("command.com");
1153 g_assert (retval != NULL);
1155 return retval;
1156 #endif
1160 * anjuta_util_user_terminal:
1162 * Retrieves the user's preferred terminal.
1164 * Returns: (transfer full): A newly allocated strings list. The first argument
1165 * is the terminal program name. The following are the arguments needed to
1166 * execute a command. The list has to be freed with g_strfreev
1168 /* copied from deprecated gnome_execute_terminal in libgnome */
1169 gchar **
1170 anjuta_util_user_terminal (void)
1172 gchar *terminal = NULL;
1173 gchar **argv = NULL;
1174 static const gchar *terms[] = {
1175 "xdg-terminal",
1176 "gnome-terminal",
1177 "nxterm",
1178 "color-xterm",
1179 "rxvt",
1180 "xterm",
1181 "dtterm",
1182 NULL
1184 const gchar **term;
1185 GSettingsSchema *schema;
1187 schema = g_settings_schema_source_lookup (g_settings_schema_source_get_default (),
1188 "org.gnome.desktop.default-applications.terminal",
1189 TRUE);
1191 if (schema)
1193 GSettings *settings = g_settings_new ("org.gnome.desktop.default-applications.terminal");
1195 argv = g_new0 (gchar *, 3);
1196 argv[0] = g_settings_get_string (settings, "exec");
1197 argv[1] = g_settings_get_string (settings, "exec-arg");
1199 g_settings_schema_unref (schema);
1200 g_object_unref (settings);
1202 return argv;
1206 /* Search for common ones */
1207 for (term = terms; *term != NULL; term++)
1209 terminal = g_find_program_in_path (*term);
1210 if (terminal != NULL) break;
1213 /* Try xterm */
1214 g_warning (_("Cannot find a terminal; using "
1215 "xterm, even if it may not work"));
1216 terminal = g_strdup ("xterm");
1218 argv = g_new0 (char *, 3);
1219 argv[0] = terminal;
1220 /* Note that gnome-terminal takes -x and
1221 * as -e in gnome-terminal is broken we use that. */
1222 argv[1] = g_strdup (term == &terms[2] ? "-x" : "-e");
1224 return argv;
1227 static void
1228 close_pid (GPid pid,
1229 gint status,
1230 gpointer user_data)
1232 g_spawn_close_pid (pid);
1235 GPid
1236 anjuta_util_execute_shell (const gchar *dir, const gchar *command)
1238 GPid pid;
1239 gchar **argv;
1240 GError *error = NULL;
1242 g_return_val_if_fail (command != NULL, -1);
1244 argv = g_new0 (gchar *, 4);
1246 argv[0] = anjuta_util_user_shell ();
1247 #ifndef G_OS_WIN32
1248 argv[1] = g_strdup ("-c");
1249 #else
1250 argv[2] = g_strdup ("/C");
1251 #endif
1252 argv[3] = g_strdup (command);
1254 if (dir)
1255 anjuta_util_create_dir (dir);
1257 if (!g_spawn_async (dir, argv, NULL,
1258 G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
1259 NULL, NULL, &pid, &error))
1261 g_warning (_("Cannot execute command: %s (using shell %s): %s\n"),
1262 command, argv[0], error->message);
1263 pid = 0;
1266 g_child_watch_add (pid, close_pid, NULL);
1268 g_strfreev (argv);
1270 // Anjuta will take care of child exit automatically.
1271 return pid;
1274 GPid
1275 anjuta_util_execute_terminal_shell (const gchar *dir, const gchar *command)
1277 GPid pid;
1278 gchar *shell;
1279 gchar **term_argv;
1280 gchar **argv;
1281 gint i;
1282 GError *error = NULL;
1284 g_return_val_if_fail (command != NULL, -1);
1286 shell = anjuta_util_user_shell ();
1287 term_argv = anjuta_util_user_terminal ();
1288 argv = g_new0 (gchar *, g_strv_length (term_argv) + 4);
1290 i = 0;
1291 if (term_argv)
1293 for (; term_argv [i]; i++)
1294 argv[i] = term_argv[i];
1297 argv[i++] = shell;
1298 #ifndef G_OS_WIN32
1299 argv[i++] = g_strdup ("-c");
1300 #else
1301 argv[i++] = g_strdup ("/C");
1302 #endif
1303 argv[i++] = g_strdup (command);
1305 if (dir)
1306 anjuta_util_create_dir (dir);
1308 if (!g_spawn_async (dir, argv, NULL,
1309 G_SPAWN_SEARCH_PATH | G_SPAWN_DO_NOT_REAP_CHILD,
1310 NULL, NULL, &pid, &error))
1312 g_warning (_("Cannot execute command: %s (using shell %s): %s\n"),
1313 command, shell, error->message);
1314 pid = 0;
1317 g_child_watch_add (pid, close_pid, NULL);
1319 g_strfreev (argv);
1320 g_free (term_argv);
1322 // Anjuta will take care of child exit automatically.
1323 return pid;
1326 gchar *
1327 anjuta_util_convert_to_utf8 (const gchar *str)
1329 GError *error = NULL;
1330 gchar *utf8_msg_string = NULL;
1332 g_return_val_if_fail (str != NULL, NULL);
1333 g_return_val_if_fail (strlen (str) > 0, NULL);
1335 if (g_utf8_validate(str, -1, NULL))
1337 utf8_msg_string = g_strdup (str);
1339 else
1341 gsize rbytes, wbytes;
1342 utf8_msg_string = g_locale_to_utf8 (str, -1, &rbytes, &wbytes, &error);
1343 if (error != NULL) {
1344 g_warning ("g_locale_to_utf8 failed: %s\n", error->message);
1345 g_error_free (error);
1346 /* g_free (utf8_msg_string);
1347 return NULL; */
1350 return utf8_msg_string;
1353 #define LEFT_BRACE(ch) (ch == ')'? '(' : (ch == '}'? '{' : (ch == ']'? '[' : ch)))
1355 gboolean
1356 anjuta_util_jump_to_matching_brace (IAnjutaIterable *iter, gchar brace, gint limit)
1358 gchar point_ch = brace;
1359 gint cur_iteration = 0;
1360 gboolean use_limit = (limit > 0);
1361 GString *braces_stack = g_string_new ("");
1363 g_return_val_if_fail (point_ch == ')' || point_ch == ']' ||
1364 point_ch == '}', FALSE);
1366 /* DEBUG_PRINT ("%s", "Matching brace being"); */
1367 /* Push brace */
1368 g_string_prepend_c (braces_stack, point_ch);
1370 while (ianjuta_iterable_previous (iter, NULL))
1372 /* Check limit */
1373 cur_iteration++;
1374 if (use_limit && cur_iteration > limit)
1375 break;
1377 /* Skip comments and strings */
1378 IAnjutaEditorAttribute attrib =
1379 ianjuta_editor_cell_get_attribute (IANJUTA_EDITOR_CELL (iter), NULL);
1380 if (attrib == IANJUTA_EDITOR_COMMENT || attrib == IANJUTA_EDITOR_STRING)
1381 continue;
1383 /* DEBUG_PRINT ("%s", "point ch = %c", point_ch); */
1384 point_ch = ianjuta_editor_cell_get_char (IANJUTA_EDITOR_CELL (iter), 0,
1385 NULL);
1386 if (point_ch == ')' || point_ch == ']' || point_ch == '}')
1388 /* Push brace */
1389 g_string_prepend_c (braces_stack, point_ch);
1390 continue;
1392 if (point_ch == LEFT_BRACE (braces_stack->str[0]))
1394 /* Pop brace */
1395 g_string_erase (braces_stack, 0, 1);
1397 /* Bail out if there is no more in stack */
1398 if (braces_stack->str[0] == '\0')
1400 /* DEBUG_PRINT ("%s", "Matching brace end -- found"); */
1401 return TRUE;
1404 /* DEBUG_PRINT ("%s", "Matching brace end -- not found"); */
1405 return FALSE;
1409 * anjuta_util_parse_args_from_string:
1410 * @string: arguments
1412 * Parse arguments from a string to a GList.
1414 * Returns: (element-type utf8) (transfer full): A newly allocated GList of
1415 * strings.
1417 GList*
1418 anjuta_util_parse_args_from_string (const gchar* string)
1420 gboolean escaped;
1421 gchar quote = 0;
1422 gboolean is_quote = FALSE;
1423 gchar* buffer = g_new0(gchar, strlen(string) + 1);
1424 const gchar *s;
1425 gint idx;
1426 GList* args = NULL;
1428 idx = 0;
1429 escaped = FALSE;
1430 s = string;
1432 while (*s) {
1433 if (!isspace(*s))
1434 break;
1435 s++;
1438 while (*s) {
1439 if (escaped) {
1440 /* The current char was escaped */
1441 buffer[idx++] = *s;
1442 escaped = FALSE;
1443 } else if (*s == '\\') {
1444 /* Current char is an escape */
1445 escaped = TRUE;
1446 } else if (is_quote && *s == quote) {
1447 /* Current char ends a quotation */
1448 is_quote = FALSE;
1449 if (!isspace(*(s+1)) && (*(s+1) != '\0')) {
1450 /* If there is no space after the quotation or it is not
1451 the end of the string */
1452 g_warning ("Parse error while parsing program arguments");
1454 } else if ((*s == '\"' || *s == '\'')) {
1455 if (!is_quote) {
1456 /* Current char starts a quotation */
1457 quote = *s;
1458 is_quote = TRUE;
1459 } else {
1460 /* Just a quote char inside quote */
1461 buffer[idx++] = *s;
1463 } else if (is_quote){
1464 /* Any other char inside quote */
1465 buffer[idx++] = *s;
1466 } else if (isspace(*s)) {
1467 /* Any white space outside quote */
1468 if (idx > 0) {
1469 buffer[idx++] = '\0';
1470 args = g_list_append (args, g_strdup (buffer));
1471 idx = 0;
1473 } else {
1474 buffer[idx++] = *s;
1476 s++;
1478 if (idx > 0) {
1479 /* There are chars in the buffer. Flush as the last arg */
1480 buffer[idx++] = '\0';
1481 args = g_list_append (args, g_strdup (buffer));
1482 idx = 0;
1484 if (is_quote) {
1485 g_warning ("Unclosed quotation encountered at the end of parsing");
1487 g_free (buffer);
1488 return args;
1491 gchar*
1492 anjuta_util_escape_quotes(const gchar* str)
1494 gchar *buffer;
1495 gint idx, max_size;
1496 const gchar *s = str;
1498 g_return_val_if_fail(str, NULL);
1499 idx = 0;
1501 /* We are assuming there will be less than 2048 chars to escape */
1502 max_size = strlen(str) + 2048;
1503 buffer = g_new (gchar, max_size);
1504 max_size -= 2;
1506 while(*s) {
1507 if (idx > max_size)
1508 break;
1509 if (*s == '\"' || *s == '\'' || *s == '\\')
1510 buffer[idx++] = '\\';
1511 buffer[idx++] = *s;
1512 s++;
1514 buffer[idx] = '\0';
1515 return buffer;
1518 /* Diff the text contained in uri with text. Return true if files
1519 differ, FALSE if they are identical.*/
1521 gboolean anjuta_util_diff(const gchar* uri, const gchar* text)
1523 GFile *file;
1524 GFileInfo *file_info;
1525 guint64 size;
1526 gchar* file_text = NULL;
1527 gsize bytes_read;
1529 file = g_file_new_for_uri (uri);
1530 file_info = g_file_query_info (file,
1531 G_FILE_ATTRIBUTE_STANDARD_SIZE,
1532 G_FILE_QUERY_INFO_NONE,
1533 NULL,
1534 NULL);
1536 if (file_info == NULL)
1538 g_object_unref (file);
1539 return TRUE;
1542 size = g_file_info_get_attribute_uint64(file_info,
1543 G_FILE_ATTRIBUTE_STANDARD_SIZE);
1544 g_object_unref (file_info);
1546 if (size == 0 && text == NULL)
1548 g_object_unref (file);
1549 return FALSE;
1551 else if (size == 0 || text == NULL)
1553 g_object_unref (file);
1554 return TRUE;
1557 if (!g_file_load_contents(file,
1558 NULL,
1559 &file_text,
1560 &bytes_read,
1561 NULL,
1562 NULL))
1564 g_object_unref (file);
1565 return TRUE;
1567 g_object_unref (file);
1569 if (bytes_read != size)
1571 g_free (file_text);
1572 return TRUE;
1575 /* according to g_file_load_contents's documentation
1576 * file_text is guaranteed to end with \0.
1578 if (strcmp (file_text, text) == 0)
1580 g_free (file_text);
1581 return FALSE;
1584 g_free (file_text);
1585 return TRUE;
1589 * anjuta_util_is_project_file:
1590 * @filename: the file name
1592 * Return %TRUE if the file is an anjuta project file. It is implemented by
1593 * checking only the file extension. So it does not check the existence
1594 * of the file. But it is working on an URI if it does not containt a
1595 * fragment.
1597 * Returns: %TRUE if the file is a project file, else %FALSE
1599 gboolean
1600 anjuta_util_is_project_file (const gchar *filename)
1602 gsize len = strlen (filename);
1603 return ((len > 8) && (strcmp (filename + len - 7, ".anjuta") == 0));
1607 * anjuta_util_is_template_file:
1608 * @filename: the file name
1610 * Return %TRUE if the file is an template project file. It is implemented by
1611 * checking only the file extension. So it does not check the existence
1612 * of the file. But it is working on an URI if it does not containt a
1613 * fragment.
1615 * Returns: %TRUE if the file is a template file, else %FALSE
1617 gboolean
1618 anjuta_util_is_template_file (const gchar *filename)
1620 gsize len = strlen (filename);
1621 return ((len > 9) && (strcmp (filename + len - 8, ".wiz.tgz") == 0));
1625 * anjuta_util_get_file_info_mine_type:
1626 * @info: the file information object
1628 * Return the mime type corresponding to a file infor object.
1630 * Returns: (transfer full) (allow-none): The mime type as a newly allocated
1631 * string that must be freed with g_free() or %NULL if the mime type cannot be found.
1633 gchar *
1634 anjuta_util_get_file_info_mime_type (GFileInfo *info)
1636 gchar *mime_type = NULL;
1637 const gchar *extension;
1638 const gchar *name;
1640 g_return_val_if_fail (info != NULL, NULL);
1643 /* If Anjuta is not installed in system gnome prefix, the mime types
1644 * may not have been correctly registed. In that case, we use the
1645 * following mime detection
1647 name = g_file_info_get_name (info);
1648 extension = strrchr(name, '.');
1649 if ((extension != NULL) && (extension != name))
1651 const static struct {gchar *extension; gchar *type;} anjuta_types[] = {
1652 {"anjuta", "application/x-anjuta"},
1653 {"prj", "application/x-anjuta-old"},
1654 {NULL, NULL}};
1655 gint i;
1657 for (i = 0; anjuta_types[i].extension != NULL; i++)
1659 if (strcmp(extension + 1, anjuta_types[i].extension) == 0)
1661 mime_type = g_strdup (anjuta_types[i].type);
1662 break;
1667 /* Use mime database if it is not an Anjuta type */
1668 if (mime_type == NULL)
1670 mime_type = g_content_type_get_mime_type (g_file_info_get_content_type(info));
1673 return mime_type;
1677 * anjuta_util_get_file_mine_type:
1678 * @file: the file
1680 * Check if a file exists and return its mime type.
1682 * Returns: (transfer full) (allow-none): %NULL if the corresponding file doesn't
1683 * exist or the mime type as a newly allocated string that must be freed with
1684 * g_free().
1686 gchar *
1687 anjuta_util_get_file_mime_type (GFile *file)
1689 GFileInfo *info;
1690 gchar *mime_type = NULL;
1692 g_return_val_if_fail (file != NULL, NULL);
1694 /* Get file information, check that the file exist at the same time */
1695 info = g_file_query_info (file,
1696 G_FILE_ATTRIBUTE_STANDARD_NAME ","
1697 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
1698 G_FILE_QUERY_INFO_NONE,
1699 NULL,
1700 NULL);
1702 if (info != NULL)
1704 mime_type = anjuta_util_get_file_info_mime_type (info);
1705 g_object_unref (info);
1708 return mime_type;
1711 gchar *
1712 anjuta_util_get_local_path_from_uri (const gchar *uri)
1714 GFile *file;
1715 gchar *local_path;
1717 file = g_file_new_for_uri (uri);
1718 local_path = g_file_get_path (file);
1719 g_object_unref (file);
1721 return local_path;
1724 #ifdef EMULATE_FORKPTY
1725 #include <grp.h>
1727 static int ptym_open (char *pts_name);
1728 static int ptys_open (int fdm, char * pts_name);
1731 login_tty(int ttyfd)
1733 int fd;
1734 char *fdname;
1736 #ifdef HAVE_SETSID
1737 setsid();
1738 #endif
1739 #ifdef HAVE_SETPGID
1740 setpgid(0, 0);
1741 #endif
1743 /* First disconnect from the old controlling tty. */
1744 #ifdef TIOCNOTTY
1745 fd = open("/dev/tty", O_RDWR|O_NOCTTY);
1746 if (fd >= 0)
1748 ioctl(fd, TIOCNOTTY, NULL);
1749 close(fd);
1751 else
1752 //syslog(LOG_WARNING, "NO CTTY");
1753 #endif /* TIOCNOTTY */
1755 /* Verify that we are successfully disconnected from the controlling tty. */
1756 fd = open("/dev/tty", O_RDWR|O_NOCTTY);
1757 if (fd >= 0)
1759 //syslog(LOG_WARNING, "Failed to disconnect from controlling tty.");
1760 close(fd);
1763 /* Make it our controlling tty. */
1764 #ifdef TIOCSCTTY
1765 ioctl(ttyfd, TIOCSCTTY, NULL);
1766 #endif /* TIOCSCTTY */
1768 fdname = ttyname (ttyfd);
1769 fd = open(fdname, O_RDWR);
1770 if (fd < 0)
1771 ;//syslog(LOG_WARNING, "open %s: %s", fdname, strerror(errno));
1772 else
1773 close(fd);
1775 /* Verify that we now have a controlling tty. */
1776 fd = open("/dev/tty", O_WRONLY);
1777 if (fd < 0)
1779 //syslog(LOG_WARNING, "open /dev/tty: %s", strerror(errno));
1780 return 1;
1783 close(fd);
1784 #if defined(HAVE_VHANGUP) && !defined(HAVE_REVOKE)
1786 RETSIGTYPE (*sig)();
1787 sig = signal(SIGHUP, SIG_IGN);
1788 vhangup();
1789 signal(SIGHUP, sig);
1791 #endif
1792 fd = open(fdname, O_RDWR);
1793 if (fd == -1)
1795 //syslog(LOG_ERR, "can't reopen ctty %s: %s", fdname, strerror(errno));
1796 return -1;
1799 close(ttyfd);
1801 if (fd != 0)
1802 close(0);
1803 if (fd != 1)
1804 close(1);
1805 if (fd != 2)
1806 close(2);
1808 dup2(fd, 0);
1809 dup2(fd, 1);
1810 dup2(fd, 2);
1811 if (fd > 2)
1812 close(fd);
1813 return 0;
1817 openpty(int *amaster, int *aslave, char *name, struct termios *termp,
1818 struct winsize *winp)
1820 char line[20];
1821 *amaster = ptym_open(line);
1822 if (*amaster < 0)
1823 return -1;
1824 *aslave = ptys_open(*amaster, line);
1825 if (*aslave < 0) {
1826 close(*amaster);
1827 return -1;
1829 if (name)
1830 strcpy(name, line);
1831 #ifndef TCSAFLUSH
1832 #define TCSAFLUSH TCSETAF
1833 #endif
1834 if (termp)
1835 (void) tcsetattr(*aslave, TCSAFLUSH, termp);
1836 #ifdef TIOCSWINSZ
1837 if (winp)
1838 (void) ioctl(*aslave, TIOCSWINSZ, (char *)winp);
1839 #endif
1840 return 0;
1843 static int
1844 ptym_open(char * pts_name)
1846 int fdm;
1847 #ifdef HAVE_PTSNAME
1848 char *ptr;
1850 strcpy(pts_name, "/dev/ptmx");
1851 fdm = open(pts_name, O_RDWR);
1852 if (fdm < 0)
1853 return -1;
1854 if (grantpt(fdm) < 0) { /* grant access to slave */
1855 close(fdm);
1856 return -2;
1858 if (unlockpt(fdm) < 0) { /* clear slave's lock flag */
1859 close(fdm);
1860 return -3;
1862 ptr = ptsname(fdm);
1863 if (ptr == NULL) { /* get slave's name */
1864 close (fdm);
1865 return -4;
1867 strcpy(pts_name, ptr); /* return name of slave */
1868 return fdm; /* return fd of master */
1869 #else
1870 char *ptr1, *ptr2;
1872 strcpy(pts_name, "/dev/ptyXY");
1873 /* array index: 012345689 (for references in following code) */
1874 for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1 != 0; ptr1++) {
1875 pts_name[8] = *ptr1;
1876 for (ptr2 = "0123456789abcdef"; *ptr2 != 0; ptr2++) {
1877 pts_name[9] = *ptr2;
1878 /* try to open master */
1879 fdm = open(pts_name, O_RDWR);
1880 if (fdm < 0) {
1881 if (errno == ENOENT) /* different from EIO */
1882 return -1; /* out of pty devices */
1883 else
1884 continue; /* try next pty device */
1886 pts_name[5] = 't'; /* chage "pty" to "tty" */
1887 return fdm; /* got it, return fd of master */
1890 return -1; /* out of pty devices */
1891 #endif
1894 static int
1895 ptys_open(int fdm, char * pts_name)
1897 int fds;
1898 #ifdef HAVE_PTSNAME
1899 /* following should allocate controlling terminal */
1900 fds = open(pts_name, O_RDWR);
1901 if (fds < 0) {
1902 close(fdm);
1903 return -5;
1905 if (ioctl(fds, I_PUSH, "ptem") < 0) {
1906 close(fdm);
1907 close(fds);
1908 return -6;
1910 if (ioctl(fds, I_PUSH, "ldterm") < 0) {
1911 close(fdm);
1912 close(fds);
1913 return -7;
1915 if (ioctl(fds, I_PUSH, "ttcompat") < 0) {
1916 close(fdm);
1917 close(fds);
1918 return -8;
1921 if (ioctl(fdm, I_PUSH, "pckt") < 0) {
1922 close(fdm);
1923 close(fds);
1924 return -8;
1927 if (ioctl(fdm, I_SRDOPT, RMSGN|RPROTDAT) < 0) {
1928 close(fdm);
1929 close(fds);
1930 return -8;
1933 return fds;
1934 #else
1935 int gid;
1936 struct group *grptr;
1938 grptr = getgrnam("tty");
1939 if (grptr != NULL)
1940 gid = grptr->gr_gid;
1941 else
1942 gid = -1; /* group tty is not in the group file */
1943 /* following two functions don't work unless we're root */
1944 chown(pts_name, getuid(), gid);
1945 chmod(pts_name, S_IRUSR | S_IWUSR | S_IWGRP);
1946 fds = open(pts_name, O_RDWR);
1947 if (fds < 0) {
1948 close(fdm);
1949 return -1;
1951 return fds;
1952 #endif
1956 forkpty(int *amaster, char *name, struct termios *termp, struct winsize *winp)
1958 int master, slave, pid;
1960 if (openpty(&master, &slave, name, termp, winp) == -1)
1961 return (-1);
1962 switch (pid = fork()) {
1963 case -1:
1964 return (-1);
1965 case 0:
1967 * child
1969 close(master);
1970 login_tty(slave);
1971 return (0);
1974 * parent
1976 *amaster = master;
1977 close(slave);
1978 return (pid);
1981 int scandir(const char *dir, struct dirent ***namelist,
1982 int (*select)(const struct dirent *),
1983 int (*compar)(const struct dirent **, const struct dirent **))
1985 DIR *d;
1986 struct dirent *entry;
1987 register int i=0;
1988 size_t entrysize;
1990 if ((d=opendir(dir)) == NULL)
1991 return(-1);
1993 *namelist=NULL;
1994 while ((entry=readdir(d)) != NULL)
1996 if (select == NULL || (select != NULL && (*select)(entry)))
1998 *namelist=(struct dirent **)realloc((void *)(*namelist),
1999 (size_t)((i+1)*sizeof(struct dirent *)));
2000 if (*namelist == NULL) return(-1);
2001 entrysize=sizeof(struct dirent)-sizeof(entry->d_name)+strlen(entry->d_name)+1;
2002 (*namelist)[i]=(struct dirent *)malloc(entrysize);
2003 if ((*namelist)[i] == NULL) return(-1);
2004 memcpy((*namelist)[i], entry, entrysize);
2005 i++;
2008 if (closedir(d)) return(-1);
2009 if (i == 0) return(-1);
2010 if (compar != NULL)
2011 qsort((void *)(*namelist), (size_t)i, sizeof(struct dirent *), compar);
2013 return(i);
2016 #endif /* EMULATE_FORKPTY */
2018 void
2019 anjuta_util_help_display (GtkWidget *parent,
2020 const gchar *doc_id,
2021 const gchar *item)
2023 GError *error = NULL;
2024 gchar *command;
2027 command = g_strdup_printf ("yelp help:%s%s%s",
2028 doc_id,
2029 item == NULL ? "" : "/",
2030 item == NULL ? "" : item);
2032 if (!g_spawn_command_line_async (command, &error) &&
2033 (error != NULL))
2035 g_warning ("Error executing help application: %s",
2036 error->message);
2037 g_error_free (error);
2039 g_free (command);
2043 /* The following functions are taken from gedit */
2045 /* Note that this function replace home dir with ~ */
2046 gchar *
2047 anjuta_util_uri_get_dirname (const gchar *uri)
2049 gchar *res;
2050 gchar *str;
2052 // CHECK: does it work with uri chaining? - Paolo
2053 str = g_path_get_dirname (uri);
2054 g_return_val_if_fail (str != NULL, ".");
2056 if ((strlen (str) == 1) && (*str == '.'))
2058 g_free (str);
2060 return NULL;
2063 res = anjuta_util_replace_home_dir_with_tilde (str);
2065 g_free (str);
2067 return res;
2070 gchar*
2071 anjuta_util_replace_home_dir_with_tilde (const gchar *uri)
2073 gchar *tmp;
2074 gchar *home;
2076 g_return_val_if_fail (uri != NULL, NULL);
2078 /* Note that g_get_home_dir returns a const string */
2079 tmp = (gchar *)g_get_home_dir ();
2081 if (tmp == NULL)
2082 return g_strdup (uri);
2084 home = g_filename_to_utf8 (tmp, -1, NULL, NULL, NULL);
2085 if (home == NULL)
2086 return g_strdup (uri);
2088 if (strcmp (uri, home) == 0)
2090 g_free (home);
2092 return g_strdup ("~");
2095 tmp = home;
2096 home = g_strdup_printf ("%s/", tmp);
2097 g_free (tmp);
2099 if (g_str_has_prefix (uri, home))
2101 gchar *res;
2103 res = g_strdup_printf ("~/%s", uri + strlen (home));
2105 g_free (home);
2107 return res;
2110 g_free (home);
2112 return g_strdup (uri);
2116 * anjuta_util_shell_expand:
2117 * @string: input string
2119 * Expand environment variables $(var_name) and tilde (~) in the input string.
2121 * Returns: (transfer full): a newly-allocated string that must be freed with g_free().
2123 gchar*
2124 anjuta_util_shell_expand (const gchar *string)
2126 GString* expand;
2128 if (string == NULL) return NULL;
2130 expand = g_string_sized_new (strlen (string));
2132 for (; *string != '\0'; string++)
2134 switch (*string)
2136 case '$':
2138 /* Variable expansion */
2139 const gchar *end;
2140 gint var_name_len;
2142 end = string + 1;
2143 while (isalnum (*end) || (*end == '_')) end++;
2144 var_name_len = end - string - 1;
2145 if (var_name_len > 0)
2147 const gchar *value;
2149 g_string_append_len (expand, string + 1, var_name_len);
2150 value = g_getenv (expand->str + expand->len - var_name_len);
2151 g_string_truncate (expand, expand->len - var_name_len);
2152 g_string_append (expand, value);
2153 string = end - 1;
2154 continue;
2156 break;
2158 case '~':
2160 /* User home directory expansion */
2161 if (isspace(string[1]) || (string[1] == G_DIR_SEPARATOR) || (string[1] == '\0'))
2163 g_string_append (expand, g_get_home_dir());
2164 continue;
2166 break;
2168 default:
2169 break;
2171 g_string_append_c (expand, *string);
2174 return g_string_free (expand, FALSE);
2177 gchar *
2178 anjuta_util_str_middle_truncate (const gchar *string,
2179 guint truncate_length)
2181 GString *truncated;
2182 guint length;
2183 guint n_chars;
2184 guint num_left_chars;
2185 guint right_offset;
2186 guint delimiter_length;
2187 const gchar *delimiter = "\342\200\246";
2189 g_return_val_if_fail (string != NULL, NULL);
2191 length = strlen (string);
2193 g_return_val_if_fail (g_utf8_validate (string, length, NULL), NULL);
2195 /* It doesnt make sense to truncate strings to less than
2196 * the size of the delimiter plus 2 characters (one on each
2197 * side)
2199 delimiter_length = g_utf8_strlen (delimiter, -1);
2200 if (truncate_length < (delimiter_length + 2)) {
2201 return g_strdup (string);
2204 n_chars = g_utf8_strlen (string, length);
2206 /* Make sure the string is not already small enough. */
2207 if (n_chars <= truncate_length) {
2208 return g_strdup (string);
2211 /* Find the 'middle' where the truncation will occur. */
2212 num_left_chars = (truncate_length - delimiter_length) / 2;
2213 right_offset = n_chars - truncate_length + num_left_chars + delimiter_length;
2215 truncated = g_string_new_len (string,
2216 g_utf8_offset_to_pointer (string, num_left_chars) - string);
2217 g_string_append (truncated, delimiter);
2218 g_string_append (truncated, g_utf8_offset_to_pointer (string, right_offset));
2220 return g_string_free (truncated, FALSE);
2224 * Functions to implement XDG Base Directory Specification
2225 * http://standards.freedesktop.org/basedir-spec/latest/index.html
2226 * Use this to save any config/cache/data files
2230 void
2231 anjuta_util_set_anjuta_prefix (const gchar *prefix)
2233 anjuta_prefix = g_strdup (prefix);
2236 static gchar*
2237 anjuta_util_construct_pathv (const gchar* str, va_list str_list)
2239 GPtrArray *str_arr;
2240 const gchar* tmp_str;
2241 gchar* path;
2243 str_arr = g_ptr_array_new();
2244 g_ptr_array_add (str_arr, (gpointer) str);
2246 /* Extract elements from va_list */
2247 if (str != NULL)
2249 while ((tmp_str = va_arg (str_list, const gchar*)) != NULL)
2251 g_ptr_array_add (str_arr, (gpointer)tmp_str);
2253 va_end (str_list);
2256 /* Terminate the list */
2257 g_ptr_array_add (str_arr, NULL);
2259 path = g_build_filenamev ((gchar **)str_arr->pdata);
2260 g_ptr_array_free (str_arr, TRUE);
2262 return path;
2265 static GFile*
2266 anjuta_util_get_user_cache_filev (const gchar* path, va_list list)
2268 gchar *uri_str, *base_path, *dir;
2269 GFile *uri;
2270 base_path = g_build_filename (g_get_user_cache_dir(), anjuta_prefix, path, NULL);
2272 uri_str = anjuta_util_construct_pathv (base_path, list);
2273 g_free (base_path);
2275 uri = g_file_new_for_path (uri_str);
2276 dir = g_path_get_dirname (uri_str);
2277 g_free(uri_str);
2278 if (!anjuta_util_create_dir (dir)) return NULL;
2280 return uri;
2283 GFile*
2284 anjuta_util_get_user_cache_file (const gchar* path, ...)
2286 va_list list;
2287 va_start (list, path);
2288 return anjuta_util_get_user_cache_filev (path, list);
2291 static GFile*
2292 anjuta_util_get_user_config_filev (const gchar* path, va_list list)
2294 gchar *uri_str, *base_path, *dir;
2295 GFile *uri;
2296 base_path = g_build_filename (g_get_user_config_dir(), anjuta_prefix, path, NULL);
2298 uri_str = anjuta_util_construct_pathv (base_path, list);
2299 g_free (base_path);
2301 uri = g_file_new_for_path (uri_str);
2302 dir = g_path_get_dirname (uri_str);
2303 g_free(uri_str);
2304 if (!anjuta_util_create_dir (dir)) return NULL;
2306 return uri;
2309 GFile*
2310 anjuta_util_get_user_config_file (const gchar* path, ...)
2312 va_list list;
2313 va_start (list, path);
2314 return anjuta_util_get_user_config_filev (path, list);
2317 static GFile*
2318 anjuta_util_get_user_data_filev (const gchar* path, va_list list)
2320 gchar *uri_str, *base_path, *dir;
2321 GFile *uri;
2322 base_path = g_build_filename (g_get_user_data_dir(), anjuta_prefix, path, NULL);
2324 uri_str = anjuta_util_construct_pathv (base_path, list);
2325 g_free (base_path);
2327 uri = g_file_new_for_path (uri_str);
2328 dir = g_path_get_dirname (uri_str);
2329 g_free(uri_str);
2330 if (!anjuta_util_create_dir (dir)) return NULL;
2332 return uri;
2335 GFile*
2336 anjuta_util_get_user_data_file (const gchar* path, ...)
2338 va_list list;
2339 va_start (list, path);
2340 return anjuta_util_get_user_data_filev (path, list);
2343 gchar*
2344 anjuta_util_get_user_cache_file_path (const gchar* path, ...)
2346 va_list list;
2347 GFile *file;
2348 gchar *file_path;
2349 va_start (list, path);
2350 file = anjuta_util_get_user_cache_filev (path, list);
2351 file_path = g_file_get_path (file);
2352 g_object_unref (file);
2354 return file_path;
2357 gchar*
2358 anjuta_util_get_user_config_file_path (const gchar* path, ...)
2360 va_list list;
2361 GFile *file;
2362 gchar *file_path;
2363 va_start (list, path);
2364 file = anjuta_util_get_user_config_filev (path, list);
2365 file_path = g_file_get_path (file);
2366 g_object_unref (file);
2368 return file_path;
2371 gchar*
2372 anjuta_util_get_user_data_file_path (const gchar* path, ...)
2374 va_list list;
2375 GFile *file;
2376 gchar *file_path;;
2377 va_start (list, path);
2378 file = anjuta_util_get_user_data_filev (path, list);
2379 file_path = g_file_get_path (file);
2380 g_object_unref (file);
2382 return file_path;
2385 GList *
2386 anjuta_util_convert_gfile_list_to_path_list (GList *list)
2388 GList *path_list;
2389 GList *current_file;
2390 gchar *path;
2392 path_list = NULL;
2394 for (current_file = list; current_file != NULL; current_file = g_list_next (current_file))
2396 path = g_file_get_path (current_file->data);
2398 /* Ignore files with invalid paths */
2399 if (path)
2400 path_list = g_list_append (path_list, path);
2403 return path_list;
2406 GList *
2407 anjuta_util_convert_gfile_list_to_relative_path_list (GList *list,
2408 const gchar *parent)
2410 GFile *parent_file;
2411 GList *path_list;
2412 GList *current_file;
2413 gchar *path;
2415 parent_file = g_file_new_for_path (parent);
2416 path_list = NULL;
2418 if (parent_file)
2420 for (current_file = list; current_file != NULL; current_file = g_list_next (current_file))
2422 path = g_file_get_relative_path (parent_file, current_file->data);
2424 /* Ignore files with invalid paths */
2425 if (path)
2426 path_list = g_list_append (path_list, path);
2429 g_object_unref (parent_file);
2432 return path_list;
2437 * anjuta_util_builder_new:
2438 * @filename: Builder file name to open
2439 * @error: Optional error object, if %NULL display a dialog if the file is missing
2441 * Create a new GtkBuilder object and load the file in it. Display an error
2442 * if the file is missing. Use a dialog if error is %NULL, just a warning
2443 * if the error can be reported.
2445 * Returns: The new GtkBuilder object
2447 GtkBuilder *
2448 anjuta_util_builder_new (const gchar *filename, GError **error)
2450 GtkBuilder *bxml = gtk_builder_new ();
2451 GError *err = NULL;
2453 /* Load glade file */
2454 if (!gtk_builder_add_from_file (bxml, filename, &err))
2456 g_object_unref (bxml);
2457 bxml = NULL;
2459 /* Display the error to the user if it cannot be reported to the caller */
2460 if (error == NULL)
2462 anjuta_util_dialog_error (NULL, _("Unable to load user interface file: %s"), err->message);
2464 else
2466 g_warning ("Couldn't load builder file: %s", err->message);
2468 g_propagate_error (error, err);
2471 /* Tag the builder object with the filename to allow better error message
2472 * with the following function */
2473 if (bxml != NULL)
2475 g_object_set_data_full (G_OBJECT (bxml), "filename", g_strdup (filename), g_free);
2478 return bxml;
2482 * anjuta_util_builder_get_objects:
2483 * @builder: Builder object
2484 * @first_widget: Name of first widget to get
2485 * ...: Address to store the first widget pointer, followed optionally by
2486 * more name/pointer pairs, followed by %NULL
2488 * Create a new GtkBuilder object and load the file in it. Display an error
2489 * if the file is missing. Use a dialog if error is %NULL, just a warning
2490 * if the error can be reported.
2492 * Returns: %TRUE is everything works as expected.
2494 gboolean
2495 anjuta_util_builder_get_objects (GtkBuilder *builder, const gchar *first_widget,...)
2497 va_list args;
2498 const gchar *name;
2499 GObject **object_ptr;
2500 gboolean missing = FALSE;
2502 va_start (args, first_widget);
2504 for (name = first_widget; name; name = va_arg (args, char *))
2506 object_ptr = va_arg (args, void *);
2507 *object_ptr = gtk_builder_get_object (builder, name);
2509 /* Object not found, display a warning */
2510 if (!*object_ptr)
2512 const gchar *filename = (const gchar *)g_object_get_data (G_OBJECT (builder), "filename");
2513 if (filename)
2515 g_warning ("Missing widget '%s' in file %s", name, filename);
2517 else
2519 g_warning("Missing widget '%s'", name);
2521 missing = TRUE;
2524 va_end (args);
2526 return !missing;
2530 * anjuta_utils_drop_get_files:
2531 * @selection_data: the #GtkSelectionData from drag_data_received
2533 * Create a list of valid uri's from a uri-list drop.
2535 * Return value: (element-type GFile*): a list of GFiles
2537 GSList*
2538 anjuta_utils_drop_get_files (GtkSelectionData *selection_data)
2540 gchar **uris;
2541 gint i;
2542 GSList* files = NULL;
2544 uris = g_uri_list_extract_uris ((gchar *) gtk_selection_data_get_data (selection_data));
2546 for (i = 0; uris[i] != NULL; i++)
2548 GFile* file = g_file_new_for_uri (uris[i]);
2549 files = g_slist_append(files, file);
2552 return files;
2556 * anjuta_util_get_user_mail:
2558 * Returns: The e-mail Address of the logged-in user. The resulting string
2559 * must be free'd after use.
2561 gchar*
2562 anjuta_util_get_user_mail()
2564 /* FIXME: Use libfolks or something like it to query the mail address */
2566 gchar *id;
2567 GSettings *settings;
2569 settings = g_settings_new (ANJUTA_PREF_SCHEMA);
2570 id = g_settings_get_string (settings, LAST_EMAIL);
2571 g_object_unref (settings);
2573 if (*id == '\0') {
2574 g_free (id);
2575 return g_strconcat(g_get_user_name (), "@", g_get_host_name (), NULL);
2577 else
2578 return id;
2582 * anjuta_util_get_user_mail:
2583 * @id: The e-mail address to be used in future
2586 void anjuta_util_set_user_mail(const gchar* id)
2588 GSettings *settings;
2590 settings = g_settings_new (ANJUTA_PREF_SCHEMA);
2591 g_settings_set_string (settings, LAST_EMAIL, id);
2592 g_object_unref (settings);
2597 * anjuta_utils_clone_string_gptrarray:
2598 * @source: The source GPtrArray containing items representing strings
2600 * Clones the contents of source GPtrArray into a new allocated GPtrArray.
2602 * Return a new allocated GPtrArray with strings g_strdup (), %NULL on error.
2603 * The returned array has set g_free as GDestroyNotity function, so that user
2604 * should only care to g_ptr_array_unref () without freeing the strings.
2606 GPtrArray *
2607 anjuta_util_clone_string_gptrarray (const GPtrArray* source)
2609 gint i;
2610 GPtrArray *dest;
2612 g_return_val_if_fail (source != NULL, NULL);
2614 dest = g_ptr_array_sized_new (source->len);
2615 g_ptr_array_set_free_func (dest, g_free);
2617 for (i = 0; i < source->len; i++)
2619 g_ptr_array_add (dest, g_strdup (g_ptr_array_index (source, i)));
2622 return dest;
2625 void
2626 anjuta_util_list_all_dir_children (GList **children, GFile *dir)
2628 GFileEnumerator *list;
2630 list = g_file_enumerate_children (dir,
2631 G_FILE_ATTRIBUTE_STANDARD_NAME,
2632 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
2633 NULL,
2634 NULL);
2636 if (list != NULL)
2638 GFileInfo *info;
2640 while ((info = g_file_enumerator_next_file (list, NULL, NULL)) != NULL)
2642 const gchar *name;
2643 GFile *file;
2645 name = g_file_info_get_name (info);
2646 file = g_file_get_child (dir, name);
2647 g_object_unref (info);
2649 if (g_file_query_file_type (file, G_FILE_QUERY_INFO_NONE, NULL) == G_FILE_TYPE_DIRECTORY)
2651 anjuta_util_list_all_dir_children (children, file);
2652 g_object_unref (file);
2654 else
2656 *children = g_list_prepend (*children, file);
2659 g_file_enumerator_close (list, NULL, NULL);
2660 g_object_unref (list);
2664 GPtrArray *
2665 anjuta_util_convert_string_list_to_array (GList *list)
2667 GList *node;
2668 GPtrArray *res;
2670 g_return_val_if_fail (list != NULL, NULL);
2672 res = g_ptr_array_new_with_free_func (g_free);
2674 node = list;
2675 while (node != NULL)
2677 g_ptr_array_add (res, g_strdup (node->data));
2679 node = g_list_next (node);
2682 return res;