project-manager: Allow to add groups to the root of directory project
[anjuta.git] / libanjuta / anjuta-utils.c
blob6a6a83bb113dfdbf047a8d4ceeb62a60f3e758d0
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 <sys/wait.h>
44 #include <dirent.h>
45 #include <unistd.h>
46 #include <stdio.h>
47 #include <string.h>
48 #ifndef G_OS_WIN32
49 #include <pwd.h>
50 #endif
52 #include <gio/gio.h>
53 #include <glib/gi18n.h>
54 #include <glib.h>
55 #include <glib/gstdio.h>
56 #include <gtk/gtk.h>
58 #include <libanjuta/anjuta-utils.h>
59 #include <libanjuta/anjuta-debug.h>
61 #define FILE_BUFFER_SIZE 1024
63 static void
64 anjuta_util_from_file_to_file (GInputStream *istream,
65 GOutputStream *ostream)
67 gsize bytes = 1;
68 GError *error = NULL;
69 gchar buffer[FILE_BUFFER_SIZE];
71 while (bytes != 0 && bytes != -1)
73 bytes = g_input_stream_read (istream, buffer,
74 sizeof (buffer),
75 NULL, &error);
76 if (error)
77 break;
79 g_output_stream_write (ostream, buffer,
80 bytes,
81 NULL, &error);
82 if (error)
83 break;
86 if (error)
88 g_warning ("%s", error->message);
89 g_error_free (error);
90 error = NULL;
93 if (!g_output_stream_close (ostream, NULL, &error))
95 g_warning ("%s", error->message);
96 g_error_free (error);
97 error = NULL;
99 if (!g_input_stream_close (istream, NULL, &error))
101 g_warning ("%s", error->message);
102 g_error_free (error);
107 * anjuta_util_copy_file:
108 * @src: the file where copy
109 * @dest: the path to copy the @src
110 * @show_error: TRUE to show a dialog error
112 * Copies @src to @dest and shows a dialog error in case is needed.
114 * Returns: TRUE if there was an error copying the file.
116 gboolean
117 anjuta_util_copy_file (const gchar * src, const gchar * dest, gboolean show_error)
119 GFile *src_file, *dest_file;
120 GFileInputStream *istream;
121 GFileOutputStream *ostream;
122 GError *error = NULL;
123 gboolean toret = FALSE;
125 src_file = g_file_new_for_path (src);
126 dest_file = g_file_new_for_path (dest);
128 istream = g_file_read (src_file, NULL, &error);
129 if (error)
130 goto free;
132 ostream = g_file_create (dest_file, G_FILE_CREATE_NONE,
133 NULL, &error);
134 if (error)
135 goto free;
137 anjuta_util_from_file_to_file (G_INPUT_STREAM (istream), G_OUTPUT_STREAM (ostream));
139 free: if (error)
141 if (show_error)
142 anjuta_util_dialog_error_system (NULL, error->code,
143 error->message);
145 g_warning ("%s", error->message);
147 toret = TRUE;
150 g_object_unref (src_file);
151 g_object_unref (dest_file);
153 return toret;
156 void
157 anjuta_util_color_from_string (const gchar * val, guint16 * r, guint16 * g, guint16 * b)
159 GdkColor color;
160 if (gdk_color_parse(val, &color))
162 *r = color.red;
163 *g = color.green;
164 *b =color.blue;
168 gchar *
169 anjuta_util_string_from_color (guint16 r, guint16 g, guint16 b)
171 return g_strdup_printf("#%02x%02x%02x", r >> 8, g >> 8, b >> 8);
174 GtkWidget*
175 anjuta_util_button_new_with_stock_image (const gchar* text,
176 const gchar* stock_id)
178 GtkWidget *button;
179 GtkWidget *child;
180 GtkStockItem item;
181 GtkWidget *label;
182 GtkWidget *image;
183 GtkWidget *hbox;
184 GtkWidget *align;
186 button = gtk_button_new ();
188 child = gtk_bin_get_child (GTK_BIN (button));
189 if (child)
190 gtk_container_remove (GTK_CONTAINER (button), child);
192 if (gtk_stock_lookup (stock_id, &item))
194 label = gtk_label_new_with_mnemonic (text);
196 gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
198 image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON);
199 hbox = gtk_hbox_new (FALSE, 2);
201 align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
203 gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
204 gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
206 gtk_container_add (GTK_CONTAINER (button), align);
207 gtk_container_add (GTK_CONTAINER (align), hbox);
208 gtk_widget_show_all (align);
210 return button;
213 label = gtk_label_new_with_mnemonic (text);
214 gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
216 gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
218 gtk_widget_show (label);
219 gtk_container_add (GTK_CONTAINER (button), label);
221 return button;
224 GtkWidget*
225 anjuta_util_dialog_add_button (GtkDialog *dialog, const gchar* text,
226 const gchar* stock_id, gint response_id)
228 GtkWidget *button;
230 g_return_val_if_fail (GTK_IS_DIALOG (dialog), NULL);
231 g_return_val_if_fail (text != NULL, NULL);
232 g_return_val_if_fail (stock_id != NULL, NULL);
234 button = anjuta_util_button_new_with_stock_image (text, stock_id);
235 g_return_val_if_fail (button != NULL, NULL);
237 gtk_widget_set_can_default (button, TRUE);
239 gtk_widget_show (button);
241 gtk_dialog_add_action_widget (dialog, button, response_id);
243 return button;
246 void
247 anjuta_util_dialog_error (GtkWindow *parent, const gchar *mesg, ...)
249 gchar* message;
250 va_list args;
251 GtkWidget *dialog;
252 GtkWindow *real_parent;
254 va_start (args, mesg);
255 message = g_strdup_vprintf (mesg, args);
256 va_end (args);
258 if (parent && GTK_IS_WINDOW (parent))
260 real_parent = parent;
262 else
264 real_parent = NULL;
267 // Dialog to be HIG compliant
268 dialog = gtk_message_dialog_new (real_parent,
269 GTK_DIALOG_DESTROY_WITH_PARENT,
270 GTK_MESSAGE_ERROR,
271 GTK_BUTTONS_CLOSE, "%s", message);
272 g_signal_connect (G_OBJECT (dialog), "response",
273 G_CALLBACK (gtk_widget_destroy), NULL);
274 gtk_widget_show (dialog);
275 g_free (message);
278 void
279 anjuta_util_dialog_warning (GtkWindow *parent, const gchar * mesg, ...)
281 gchar* message;
282 va_list args;
283 GtkWidget *dialog;
284 GtkWindow *real_parent;
286 va_start (args, mesg);
287 message = g_strdup_vprintf (mesg, args);
288 va_end (args);
290 if (parent && GTK_IS_WINDOW (parent))
292 real_parent = parent;
294 else
296 real_parent = NULL;
299 // Dialog to be HIG compliant
300 dialog = gtk_message_dialog_new (real_parent,
301 GTK_DIALOG_DESTROY_WITH_PARENT,
302 GTK_MESSAGE_WARNING,
303 GTK_BUTTONS_CLOSE, "%s", message);
304 g_signal_connect (G_OBJECT (dialog), "response",
305 G_CALLBACK (gtk_widget_destroy), NULL);
306 gtk_widget_show (dialog);
307 g_free (message);
310 void
311 anjuta_util_dialog_info (GtkWindow *parent, const gchar * mesg, ...)
313 gchar* message;
314 va_list args;
315 GtkWidget *dialog;
316 GtkWindow *real_parent;
318 va_start (args, mesg);
319 message = g_strdup_vprintf (mesg, args);
320 va_end (args);
322 if (parent && GTK_IS_WINDOW (parent))
324 real_parent = parent;
326 else
328 real_parent = NULL;
330 // Dialog to be HIG compliant
331 dialog = gtk_message_dialog_new (real_parent,
332 GTK_DIALOG_DESTROY_WITH_PARENT,
333 GTK_MESSAGE_INFO,
334 GTK_BUTTONS_CLOSE, "%s", message);
335 g_signal_connect (G_OBJECT (dialog), "response",
336 G_CALLBACK (gtk_widget_destroy), NULL);
337 gtk_widget_show (dialog);
338 g_free (message);
341 void
342 anjuta_util_dialog_error_system (GtkWindow* parent, gint errnum,
343 const gchar * mesg, ... )
345 gchar* message;
346 gchar* tot_mesg;
347 va_list args;
348 GtkWidget *dialog;
349 GtkWindow *real_parent;
351 va_start (args, mesg);
352 message = g_strdup_vprintf (mesg, args);
353 va_end (args);
355 if (0 != errnum) {
356 /* Avoid space in translated string */
357 tot_mesg = g_strconcat (message, "\n", _("System:"), " ",
358 g_strerror(errnum), NULL);
359 g_free (message);
360 } else
361 tot_mesg = message;
363 if (parent && GTK_IS_WINDOW (parent))
365 real_parent = parent;
367 else
369 real_parent = NULL;
371 // Dialog to be HIG compliant
372 dialog = gtk_message_dialog_new (real_parent,
373 GTK_DIALOG_DESTROY_WITH_PARENT,
374 GTK_MESSAGE_ERROR,
375 GTK_BUTTONS_CLOSE, "%s", tot_mesg);
376 g_signal_connect (G_OBJECT (dialog), "response",
377 G_CALLBACK (gtk_widget_destroy), NULL);
378 gtk_widget_show (dialog);
379 g_free (tot_mesg);
382 gboolean
383 anjuta_util_dialog_boolean_question (GtkWindow *parent, const gchar *mesg, ...)
385 gchar* message;
386 va_list args;
387 GtkWidget *dialog;
388 gint ret;
389 GtkWindow *real_parent;
391 va_start (args, mesg);
392 message = g_strdup_vprintf (mesg, args);
393 va_end (args);
395 if (parent && GTK_IS_WINDOW (parent))
397 real_parent = parent;
399 else
401 real_parent = NULL;
404 dialog = gtk_message_dialog_new (real_parent,
405 GTK_DIALOG_DESTROY_WITH_PARENT,
406 GTK_MESSAGE_QUESTION,
407 GTK_BUTTONS_YES_NO, "%s", message);
409 ret = gtk_dialog_run (GTK_DIALOG (dialog));
410 gtk_widget_destroy (dialog);
411 g_free (message);
413 return (ret == GTK_RESPONSE_YES);
416 gboolean
417 anjuta_util_dialog_input (GtkWindow *parent, const gchar *prompt,
418 const gchar *default_value, gchar **return_value)
420 GtkWidget *dialog, *label, *frame, *entry, *dialog_vbox, *vbox;
421 gint res;
422 gchar *markup;
423 GtkWindow *real_parent;
425 if (parent && GTK_IS_WINDOW (parent))
427 real_parent = parent;
429 else
431 real_parent = NULL;
434 dialog = gtk_dialog_new_with_buttons (prompt, real_parent,
435 GTK_DIALOG_DESTROY_WITH_PARENT,
436 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
437 GTK_STOCK_OK, GTK_RESPONSE_OK,
438 NULL);
439 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
440 dialog_vbox = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
441 gtk_window_set_default_size (GTK_WINDOW (dialog), 400, -1);
442 gtk_widget_show (dialog_vbox);
444 markup = g_strconcat ("<b>", prompt, "</b>", NULL);
445 label = gtk_label_new (NULL);
446 gtk_label_set_markup (GTK_LABEL (label), markup);
447 gtk_widget_show (label);
448 g_free (markup);
450 frame = gtk_frame_new (NULL);
451 gtk_frame_set_label_widget (GTK_FRAME (frame), label);
452 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
453 gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
454 gtk_widget_show (frame);
455 gtk_box_pack_start (GTK_BOX (dialog_vbox), frame, FALSE, FALSE, 0);
457 vbox = gtk_vbox_new (FALSE, 0);
458 gtk_widget_show (vbox);
459 gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
460 gtk_container_add (GTK_CONTAINER (frame), vbox);
462 entry = gtk_entry_new ();
463 gtk_widget_show (entry);
464 gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
465 gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
466 if (default_value)
467 gtk_entry_set_text (GTK_ENTRY (entry), default_value);
469 res = gtk_dialog_run (GTK_DIALOG (dialog));
471 if (gtk_entry_get_text (GTK_ENTRY (entry)) &&
472 strlen (gtk_entry_get_text (GTK_ENTRY (entry))) > 0)
474 *return_value = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
476 else
478 *return_value = NULL;
480 gtk_widget_destroy (dialog);
481 return (res == GTK_RESPONSE_OK);
484 static void
485 on_install_files_done (GObject *proxy, GAsyncResult *result,
486 gpointer user_data)
488 GError *error = NULL;
489 g_dbus_proxy_call_finish ((GDBusProxy *) proxy, result, &error);
490 if (error)
493 Only dbus error is handled. Rest of the errors are from packagekit
494 which have already been notified to user by packagekit.
496 if (error->domain == G_DBUS_ERROR)
498 const gchar *error_message = NULL;
500 /* Service error which implies packagekit is missing */
501 if (error->code == G_DBUS_ERROR_SERVICE_UNKNOWN)
503 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.");
505 /* General dbus error implies failure to call dbus method */
506 else if (error->code != G_DBUS_ERROR_NO_REPLY)
508 error_message = error->message;
510 if (error_message)
511 anjuta_util_dialog_error (NULL,
512 _("Installation failed: %s"),
513 error_message);
515 g_error_free (error);
519 gboolean
520 anjuta_util_install_files (const gchar * const names)
522 GDBusConnection * connection;
523 GDBusProxy * proxy;
524 guint32 xid = 0;
525 gchar ** pkgv;
527 if (!names)
528 return FALSE;
530 connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
531 if (!connection)
532 return FALSE;
534 proxy = g_dbus_proxy_new_sync (connection,
535 G_DBUS_PROXY_FLAGS_NONE,
536 NULL,
537 "org.freedesktop.PackageKit",
538 "/org/freedesktop/PackageKit",
539 "org.freedesktop.PackageKit.Modify",
540 NULL,
541 NULL);
542 if (!proxy)
543 return FALSE;
545 pkgv = g_strsplit (names, ", ", 0);
546 g_dbus_proxy_call (proxy, "InstallProvideFiles",
547 g_variant_new ("(u^ass)",
548 xid,
549 pkgv,
550 ""),
551 G_DBUS_CALL_FLAGS_NONE,
553 NULL,
554 on_install_files_done,
555 NULL);
556 g_strfreev (pkgv);
557 return TRUE;
560 gboolean
561 anjuta_util_package_is_installed (const gchar * package, gboolean show)
563 gboolean installed = FALSE;
564 int status;
565 int exit_status;
566 pid_t pid;
568 if ((pid = fork()) == 0)
569 execlp ("pkg-config", "pkg-config", "--exists", package, NULL);
571 waitpid (pid, &status, 0);
572 exit_status = WEXITSTATUS (status);
573 installed = (exit_status == 0) ? TRUE : FALSE;
574 if (installed)
575 return TRUE;
577 if (show)
579 anjuta_util_dialog_error (NULL,
580 _("The \"%s\" package is not installed.\n"
581 "Please install it."), package);
584 return FALSE;
587 gboolean
588 anjuta_util_prog_is_installed (const gchar * prog, gboolean show)
590 gchar* prog_path = g_find_program_in_path (prog);
591 if (prog_path)
593 g_free (prog_path);
594 return TRUE;
596 if (show)
598 anjuta_util_dialog_error (NULL, _("The \"%s\" utility is not installed.\n"
599 "Please install it."), prog);
601 return FALSE;
604 gchar *
605 anjuta_util_get_a_tmp_file (void)
607 static gint count = 0;
608 gchar *filename;
609 const gchar *tmpdir;
611 tmpdir = g_get_tmp_dir ();
612 filename =
613 g_strdup_printf ("%s/anjuta_%d.%d", tmpdir, count++, getpid ());
614 return filename;
617 /* GList of strings operations */
618 GList *
619 anjuta_util_glist_from_string (const gchar *string)
621 gchar *str, *temp, buff[256];
622 GList *list;
623 gchar *word_start, *word_end;
624 gboolean the_end;
626 list = NULL;
627 the_end = FALSE;
628 temp = g_strdup (string);
629 str = temp;
630 if (!str)
631 return NULL;
633 while (1)
635 gint i;
636 gchar *ptr;
638 /* Remove leading spaces */
639 while (isspace (*str) && *str != '\0')
640 str++;
641 if (*str == '\0')
642 break;
644 /* Find start and end of word */
645 word_start = str;
646 while (!isspace (*str) && *str != '\0')
647 str++;
648 word_end = str;
650 /* Copy the word into the buffer */
651 for (ptr = word_start, i = 0; ptr < word_end; ptr++, i++)
652 buff[i] = *ptr;
653 buff[i] = '\0';
654 if (strlen (buff))
655 list = g_list_append (list, g_strdup (buff));
656 if (*str == '\0')
657 break;
659 if (temp)
660 g_free (temp);
661 return list;
664 /* Prefix the strings */
665 void
666 anjuta_util_glist_strings_prefix (GList * list, const gchar *prefix)
668 GList *node;
669 node = list;
671 g_return_if_fail (prefix != NULL);
672 while (node)
674 gchar* tmp;
675 tmp = node->data;
676 node->data = g_strconcat (prefix, tmp, NULL);
677 if (tmp) g_free (tmp);
678 node = g_list_next (node);
682 /* Suffix the strings */
683 void
684 anjuta_util_glist_strings_sufix (GList * list, const gchar *sufix)
686 GList *node;
687 node = list;
689 g_return_if_fail (sufix != NULL);
690 while (node)
692 gchar* tmp;
693 tmp = node->data;
694 node->data = g_strconcat (tmp, sufix, NULL);
695 if (tmp) g_free (tmp);
696 node = g_list_next (node);
700 /* Duplicate list of strings */
701 GList*
702 anjuta_util_glist_strings_dup (GList * list)
704 GList *node;
705 GList *new_list;
707 new_list = NULL;
708 node = list;
709 while (node)
711 if (node->data)
712 new_list = g_list_append (new_list, g_strdup(node->data));
713 else
714 new_list = g_list_append (new_list, NULL);
715 node = g_list_next (node);
717 return new_list;
720 /* Join list of strings using the given delimiter */
721 gchar*
722 anjuta_util_glist_strings_join (GList * list, gchar *delimiter)
724 GString *joined;
725 gboolean first = TRUE;
726 GList *node;
728 joined = g_string_new (NULL);
729 node = list;
730 while (node)
732 if (node->data)
734 if (!first)
735 g_string_append (joined, delimiter);
736 else
737 first = FALSE;
738 g_string_append (joined, node->data);
740 node = g_list_next (node);
742 if (joined->len > 0)
743 return g_string_free (joined, FALSE);
744 else
745 g_string_free (joined, TRUE);
746 return NULL;
749 gchar*
750 anjuta_util_get_real_path (const gchar *path)
752 if (path != NULL)
754 gchar *result;
755 #ifdef PATH_MAX
756 gchar buf[PATH_MAX+1];
758 result = realpath (path, buf);
759 if (result != NULL)
761 *(buf + PATH_MAX) = '\0'; /* ensure a terminator */
762 return g_strdup (buf);
764 #else
765 char *buf;
766 /* the string returned by realpath should be cleaned with
767 free(), not g_free() */
768 buf = realpath (path, NULL);
769 if (buf != NULL)
771 result = g_strdup (buf);
772 free (buf);
773 return result;
775 #endif
777 return NULL;
781 * anjuta_util_get_current_dir:
783 * Get current working directory, unlike g_get_current_dir, keeps symbolic links
784 * in path name.
786 * Returns: The current working directory.
788 gchar*
789 anjuta_util_get_current_dir (void)
791 const gchar *pwd;
793 pwd = g_getenv ("PWD");
794 if (pwd != NULL)
796 return g_strdup (pwd);
798 else
800 return g_get_current_dir ();
804 static gboolean
805 is_valid_scheme_character (char c)
807 return g_ascii_isalnum (c) || c == '+' || c == '-' || c == '.';
810 /* Following RFC 2396, valid schemes are built like:
811 * scheme = alpha *( alpha | digit | "+" | "-" | "." )
813 static gboolean
814 has_valid_scheme (const char *uri)
816 const char *p;
818 p = uri;
820 if (!g_ascii_isalpha (*p))
821 return FALSE;
823 do {
824 p++;
825 } while (is_valid_scheme_character (*p));
827 return *p == ':';
831 * anjuta_util_file_new_for_commandline_arg:
833 * @arg: URI or relative or absolute file path
835 * Create a new file corresponding to arg, unlike g_file_new_for_commandline_arg,
836 * keeps symbolic links in path name.
838 * Returns: A new GFile object
840 GFile *
841 anjuta_util_file_new_for_commandline_arg (const gchar *arg)
843 GFile *file;
844 char *filename;
845 char *current_dir;
847 g_return_val_if_fail (arg != NULL, NULL);
849 if (g_path_is_absolute (arg))
850 return g_file_new_for_path (arg);
852 if (has_valid_scheme (arg))
853 return g_file_new_for_uri (arg);
855 current_dir = anjuta_util_get_current_dir ();
856 filename = g_build_filename (current_dir, arg, NULL);
857 g_free (current_dir);
859 file = g_file_new_for_path (filename);
860 g_free (filename);
862 return file;
866 /* Dedup a list of paths - duplicates are removed from the tail.
867 ** Useful for deduping Recent Files and Recent Projects */
868 GList*
869 anjuta_util_glist_path_dedup(GList *list)
871 GList *nlist = NULL, *tmp, *tmp1;
872 gchar *path;
873 struct stat s;
874 for (tmp = list; tmp; tmp = g_list_next(tmp))
876 path = anjuta_util_get_real_path ((const gchar *) tmp->data);
877 if (path)
879 if (stat (path, &s) != 0)
881 g_free(path);
883 else
885 for (tmp1 = nlist; tmp1; tmp1 = g_list_next(tmp1))
887 if (0 == strcmp((const char *) tmp1->data, path))
889 g_free(path);
890 path = NULL;
891 break;
894 if (path)
895 nlist = g_list_prepend(nlist, path);
899 anjuta_util_glist_strings_free(list);
900 nlist = g_list_reverse(nlist);
901 return nlist;
904 static gint
905 sort_node (gchar* a, gchar *b)
907 if ( !a && !b) return 0;
908 else if (!a) return -1;
909 else if (!b) return 1;
910 return strcmp (a, b);
913 /* Sort the list alphabatically */
914 GList*
915 anjuta_util_glist_strings_sort (GList * list)
917 return g_list_sort(list, (GCompareFunc)sort_node);
920 /* Free the strings and GList */
921 void
922 anjuta_util_glist_strings_free (GList * list)
924 g_list_foreach (list, (GFunc) g_free, NULL);
925 g_list_free (list);
929 anjuta_util_type_from_string (AnjutaUtilStringMap *map, const char *str)
931 int i = 0;
933 while (-1 != map[i].type)
935 if (0 == strcmp(map[i].name, str))
936 return map[i].type;
937 ++ i;
939 return -1;
942 const char*
943 anjuta_util_string_from_type (AnjutaUtilStringMap *map, int type)
945 int i = 0;
946 while (-1 != map[i].type)
948 if (map[i].type == type)
949 return map[i].name;
950 ++ i;
952 return "";
955 GList*
956 anjuta_util_glist_from_map (AnjutaUtilStringMap *map)
958 GList *out_list = NULL;
959 int i = 0;
960 while (-1 != map[i].type)
962 out_list = g_list_append(out_list, map[i].name);
963 ++ i;
965 return out_list;
969 GList *
970 anjuta_util_update_string_list (GList *p_list, const gchar *p_str, gint length)
972 gint i;
973 gchar *str;
974 if (!p_str)
975 return p_list;
976 for (i = 0; i < g_list_length (p_list); i++)
978 str = (gchar *) g_list_nth_data (p_list, i);
979 if (!str)
980 continue;
981 if (strcmp (p_str, str) == 0)
983 p_list = g_list_remove (p_list, str);
984 p_list = g_list_prepend (p_list, str);
985 return p_list;
988 p_list = g_list_prepend (p_list, g_strdup (p_str));
989 while (g_list_length (p_list) > length)
991 str = g_list_nth_data (p_list, g_list_length (p_list) - 1);
992 p_list = g_list_remove (p_list, str);
993 g_free (str);
995 return p_list;
998 gboolean
999 anjuta_util_create_dir (const gchar* path)
1001 GFile *dir = g_file_new_for_path (path);
1002 GError *err = NULL;
1003 gchar *parent;
1005 if (g_file_query_exists (dir, NULL))
1007 GFileInfo *info = g_file_query_info (dir,
1008 G_FILE_ATTRIBUTE_STANDARD_TYPE,
1009 G_FILE_QUERY_INFO_NONE,
1010 NULL, NULL);
1011 if (g_file_info_get_file_type (info) != G_FILE_TYPE_DIRECTORY)
1013 g_message ("Warning: %s is a file. \n "
1014 "It is trying to be treated as a directory.",g_file_get_path (dir));
1015 g_object_unref (dir);
1016 return FALSE;
1018 g_object_unref (info);
1020 else
1022 parent = g_path_get_dirname (path);
1023 if (anjuta_util_create_dir (parent))
1025 g_free (parent);
1026 if (!g_file_make_directory (dir, NULL, &err))
1028 g_warning ("Error directory:\n %s", err->message);
1029 g_object_unref (dir);
1030 return FALSE;
1033 else
1035 g_free (parent);
1036 g_object_unref (dir);
1037 return FALSE;
1040 g_object_unref (dir);
1042 return TRUE;
1046 * anjuta_util_user_shell:
1048 * Retrieves the user's preferred shell.
1050 * Returns: A newly allocated string that is the path to the shell.
1052 /* copied from deprecated gnome_util_user_shell in libgnome */
1053 gchar *
1054 anjuta_util_user_shell (void)
1056 #ifndef G_OS_WIN32
1057 struct passwd *pw;
1058 gint i;
1059 const gchar *shell;
1060 const gchar shells [][14] = {
1061 /* Note that on some systems shells can also
1062 * be installed in /usr/bin */
1063 "/bin/bash", "/usr/bin/bash",
1064 "/bin/zsh", "/usr/bin/zsh",
1065 "/bin/tcsh", "/usr/bin/tcsh",
1066 "/bin/ksh", "/usr/bin/ksh",
1067 "/bin/csh", "/bin/sh"
1070 if (geteuid () == getuid () &&
1071 getegid () == getgid ()) {
1072 /* only in non-setuid */
1073 if ((shell = g_getenv ("SHELL"))){
1074 if (access (shell, X_OK) == 0) {
1075 return g_strdup (shell);
1079 pw = getpwuid(getuid());
1080 if (pw && pw->pw_shell) {
1081 if (access (pw->pw_shell, X_OK) == 0) {
1082 return g_strdup (pw->pw_shell);
1086 for (i = 0; i != G_N_ELEMENTS (shells); i++) {
1087 if (access (shells [i], X_OK) == 0) {
1088 return g_strdup (shells[i]);
1092 /* If /bin/sh doesn't exist, your system is truly broken. */
1093 abort ();
1095 /* Placate compiler. */
1096 return NULL;
1097 #else
1098 /* g_find_program_in_path() always looks also in the Windows
1099 * and System32 directories, so it should always find either cmd.exe
1100 * or command.com.
1102 gchar *retval = g_find_program_in_path ("cmd.exe");
1104 if (retval == NULL)
1105 retval = g_find_program_in_path ("command.com");
1107 g_assert (retval != NULL);
1109 return retval;
1110 #endif
1114 * anjuta_util_user_terminal:
1116 * Retrieves the user's preferred terminal.
1118 * Returns: A newly allocated strings list. The first argument is the terminal
1119 * program name. The following are the arguments needed to execute
1120 * a command. The list has to be freed with g_strfreev
1122 /* copied from deprecated gnome_execute_terminal in libgnome */
1123 gchar **
1124 anjuta_util_user_terminal (void)
1126 /* FIXME: GSettings */
1127 #if 0
1128 GConfClient *client;
1129 gchar *terminal = NULL;
1130 gchar **argv = NULL;
1131 static const gchar *terms[] = {
1132 "xdg-terminal",
1133 "gnome-terminal",
1134 "nxterm",
1135 "color-xterm",
1136 "rxvt",
1137 "xterm",
1138 "dtterm",
1139 NULL
1141 const gchar **term;
1143 client = gconf_client_get_default ();
1144 terminal = gconf_client_get_string (client, "/desktop/gnome/applications/terminal/exec", NULL);
1145 g_object_unref (client);
1147 if (terminal)
1149 gchar *command_line;
1150 gchar *exec_flag;
1152 exec_flag = gconf_client_get_string (client, "/desktop/gnome/applications/terminal/exec_arg", NULL);
1153 command_line = g_strconcat (terminal, " ", exec_flag, NULL);
1155 g_shell_parse_argv (command_line, NULL, &argv, NULL);
1156 g_free (terminal);
1157 g_free (exec_flag);
1159 return argv;
1163 /* Search for common ones */
1164 for (term = terms; *term != NULL; term++)
1166 terminal = g_find_program_in_path (*term);
1167 if (terminal != NULL) break;
1170 /* Try xterm */
1171 g_warning (_("Cannot find a terminal; using "
1172 "xterm, even if it may not work"));
1173 terminal = g_strdup ("xterm");
1175 argv = g_new0 (char *, 3);
1176 argv[0] = terminal;
1177 /* Note that gnome-terminal takes -x and
1178 * as -e in gnome-terminal is broken we use that. */
1179 argv[1] = g_strdup (term == &terms[2] ? "-x" : "-e");
1181 return argv;
1182 #else
1183 g_warning ("anjuta_util_user_terminal: Not implemented");
1184 return NULL;
1185 #endif
1188 pid_t
1189 anjuta_util_execute_shell (const gchar *dir, const gchar *command)
1191 pid_t pid;
1192 gchar *shell;
1193 gint err;
1195 g_return_val_if_fail (command != NULL, -1);
1197 shell = anjuta_util_user_shell ();
1198 pid = fork();
1199 if (pid == 0)
1201 if(dir)
1203 anjuta_util_create_dir (dir);
1204 err = chdir (dir);
1206 execlp (shell, shell, "-c", command, NULL);
1207 g_warning (_("Cannot execute command: %s (using shell %s)\n"), command, shell);
1208 _exit(1);
1210 if (pid < 0)
1211 g_warning (_("Cannot execute command: %s (using shell %s)\n"), command, shell);
1212 g_free (shell);
1214 // Anjuta will take care of child exit automatically.
1215 return pid;
1218 pid_t
1219 anjuta_util_execute_terminal_shell (const gchar *dir, const gchar *command)
1221 pid_t pid;
1222 gchar *shell;
1223 gchar **term_argv;
1224 gint err;
1226 g_return_val_if_fail (command != NULL, -1);
1228 shell = anjuta_util_user_shell ();
1229 term_argv = anjuta_util_user_terminal ();
1230 pid = fork();
1231 if (pid == 0)
1233 if(dir)
1235 anjuta_util_create_dir (dir);
1236 err = chdir (dir);
1238 execlp (term_argv[0], term_argv[0], term_argv[1], shell, "-c", command, NULL);
1239 g_warning (_("Cannot execute command: %s (using shell %s)\n"), command, shell);
1240 _exit(1);
1242 if (pid < 0)
1243 g_warning (_("Cannot execute command: %s (using shell %s)\n"), command, shell);
1244 g_free (shell);
1245 g_strfreev (term_argv);
1247 // Anjuta will take care of child exit automatically.
1248 return pid;
1251 gchar *
1252 anjuta_util_convert_to_utf8 (const gchar *str)
1254 GError *error = NULL;
1255 gchar *utf8_msg_string = NULL;
1257 g_return_val_if_fail (str != NULL, NULL);
1258 g_return_val_if_fail (strlen (str) > 0, NULL);
1260 if (g_utf8_validate(str, -1, NULL))
1262 utf8_msg_string = g_strdup (str);
1264 else
1266 gsize rbytes, wbytes;
1267 utf8_msg_string = g_locale_to_utf8 (str, -1, &rbytes, &wbytes, &error);
1268 if (error != NULL) {
1269 g_warning ("g_locale_to_utf8 failed: %s\n", error->message);
1270 g_error_free (error);
1271 /* g_free (utf8_msg_string);
1272 return NULL; */
1275 return utf8_msg_string;
1278 GList*
1279 anjuta_util_parse_args_from_string (const gchar* string)
1281 gboolean escaped;
1282 gchar quote = 0;
1283 gboolean is_quote = FALSE;
1284 gchar* buffer = g_new0(gchar, strlen(string) + 1);
1285 const gchar *s;
1286 gint idx;
1287 GList* args = NULL;
1289 idx = 0;
1290 escaped = FALSE;
1291 s = string;
1293 while (*s) {
1294 if (!isspace(*s))
1295 break;
1296 s++;
1299 while (*s) {
1300 if (escaped) {
1301 /* The current char was escaped */
1302 buffer[idx++] = *s;
1303 escaped = FALSE;
1304 } else if (*s == '\\') {
1305 /* Current char is an escape */
1306 escaped = TRUE;
1307 } else if (is_quote && *s == quote) {
1308 /* Current char ends a quotation */
1309 is_quote = FALSE;
1310 if (!isspace(*(s+1)) && (*(s+1) != '\0')) {
1311 /* If there is no space after the quotation or it is not
1312 the end of the string */
1313 g_warning ("Parse error while parsing program arguments");
1315 } else if ((*s == '\"' || *s == '\'')) {
1316 if (!is_quote) {
1317 /* Current char starts a quotation */
1318 quote = *s;
1319 is_quote = TRUE;
1320 } else {
1321 /* Just a quote char inside quote */
1322 buffer[idx++] = *s;
1324 } else if (is_quote){
1325 /* Any other char inside quote */
1326 buffer[idx++] = *s;
1327 } else if (isspace(*s)) {
1328 /* Any white space outside quote */
1329 if (idx > 0) {
1330 buffer[idx++] = '\0';
1331 args = g_list_append (args, g_strdup (buffer));
1332 idx = 0;
1334 } else {
1335 buffer[idx++] = *s;
1337 s++;
1339 if (idx > 0) {
1340 /* There are chars in the buffer. Flush as the last arg */
1341 buffer[idx++] = '\0';
1342 args = g_list_append (args, g_strdup (buffer));
1343 idx = 0;
1345 if (is_quote) {
1346 g_warning ("Unclosed quotation encountered at the end of parsing");
1348 g_free (buffer);
1349 return args;
1352 gchar*
1353 anjuta_util_escape_quotes(const gchar* str)
1355 gchar *buffer;
1356 gint idx, max_size;
1357 const gchar *s = str;
1359 g_return_val_if_fail(str, NULL);
1360 idx = 0;
1362 /* We are assuming there will be less than 2048 chars to escape */
1363 max_size = strlen(str) + 2048;
1364 buffer = g_new (gchar, max_size);
1365 max_size -= 2;
1367 while(*s) {
1368 if (idx > max_size)
1369 break;
1370 if (*s == '\"' || *s == '\'' || *s == '\\')
1371 buffer[idx++] = '\\';
1372 buffer[idx++] = *s;
1373 s++;
1375 buffer[idx] = '\0';
1376 return buffer;
1379 /* Diff the text contained in uri with text. Return true if files
1380 differ, FALSE if they are identical.*/
1382 gboolean anjuta_util_diff(const gchar* uri, const gchar* text)
1384 GFile *file;
1385 GFileInfo *file_info;
1386 guint64 size;
1387 gchar* file_text = NULL;
1388 gsize bytes_read;
1390 file = g_file_new_for_uri (uri);
1391 file_info = g_file_query_info (file,
1392 G_FILE_ATTRIBUTE_STANDARD_SIZE,
1393 G_FILE_QUERY_INFO_NONE,
1394 NULL,
1395 NULL);
1397 if (file_info == NULL)
1399 g_object_unref (file);
1400 return TRUE;
1403 size = g_file_info_get_attribute_uint64(file_info,
1404 G_FILE_ATTRIBUTE_STANDARD_SIZE);
1405 g_object_unref (file_info);
1407 if (size == 0 && text == NULL)
1409 g_object_unref (file);
1410 return FALSE;
1412 else if (size == 0 || text == NULL)
1414 g_object_unref (file);
1415 return TRUE;
1418 if (!g_file_load_contents(file,
1419 NULL,
1420 &file_text,
1421 &bytes_read,
1422 NULL,
1423 NULL))
1425 g_object_unref (file);
1426 return TRUE;
1428 g_object_unref (file);
1430 if (bytes_read != size)
1432 g_free (file_text);
1433 return TRUE;
1436 /* according to g_file_load_contents's documentation
1437 * file_text is guaranteed to end with \0.
1439 if (strcmp (file_text, text) == 0)
1441 g_free (file_text);
1442 return FALSE;
1445 g_free (file_text);
1446 return TRUE;
1450 * anjuta_util_is_project_file:
1451 * @filename: the file name
1453 * Return TRUE if the file is an anjuta project file. It is implemented by
1454 * checking only the file extension. So it does not check the existence
1455 * of the file. But it is working on an URI if it does not containt a
1456 * fragment.
1458 * Returns: TRUE if the file is a project file, else FALSE
1460 gboolean
1461 anjuta_util_is_project_file (const gchar *filename)
1463 gsize len = strlen (filename);
1464 return ((len > 8) && (strcmp (filename + len - 7, ".anjuta") == 0));
1468 * anjuta_util_is_template_file:
1469 * @filename: the file name
1471 * Return TRUE if the file is an template project file. It is implemented by
1472 * checking only the file extension. So it does not check the existence
1473 * of the file. But it is working on an URI if it does not containt a
1474 * fragment.
1476 * Returns: TRUE if the file is a template file, else FALSE
1478 gboolean
1479 anjuta_util_is_template_file (const gchar *filename)
1481 gsize len = strlen (filename);
1482 return ((len > 9) && (strcmp (filename + len - 8, ".wiz.tgz") == 0));
1486 * anjuta_util_get_file_mine_type:
1487 * @file: the file
1489 * Check if a file exists and return its mime type.
1491 * Returns: NULL if the corresponding file doesn't exist or the mime type as a newly
1492 * allocated string that must be freed with g_free().
1494 gchar *
1495 anjuta_util_get_file_mime_type (GFile *file)
1497 GFileInfo *info;
1498 gchar *mime_type = NULL;
1500 g_return_val_if_fail (file != NULL, NULL);
1502 /* Get file information, check that the file exist at the same time */
1503 info = g_file_query_info (file,
1504 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
1505 G_FILE_QUERY_INFO_NONE,
1506 NULL,
1507 NULL);
1509 if (info != NULL)
1511 const gchar *extension;
1512 gchar *name;
1514 /* If Anjuta is not installed in system gnome prefix, the mime types
1515 * may not have been correctly registed. In that case, we use the
1516 * following mime detection
1518 name = g_file_get_basename (file);
1519 extension = strrchr(name, '.');
1520 if (extension != NULL)
1522 const static struct {gchar *extension; gchar *type;} anjuta_types[] = {
1523 {"anjuta", "application/x-anjuta"},
1524 {"prj", "application/x-anjuta-old"},
1525 {NULL, NULL}};
1526 gint i;
1528 for (i = 0; anjuta_types[i].extension != NULL; i++)
1530 if (strcmp(extension + 1, anjuta_types[i].extension) == 0)
1532 mime_type = g_strdup (anjuta_types[i].type);
1533 break;
1537 g_free (name);
1539 /* Use mime database if it is not an Anjuta type */
1540 if (mime_type == NULL)
1542 mime_type = g_content_type_get_mime_type (g_file_info_get_content_type(info));
1545 g_object_unref (info);
1548 return mime_type;
1551 gchar *
1552 anjuta_util_get_local_path_from_uri (const gchar *uri)
1554 GFile *file;
1555 gchar *local_path;
1557 file = g_file_new_for_uri (uri);
1558 local_path = g_file_get_path (file);
1559 g_object_unref (file);
1561 return local_path;
1564 #ifdef EMULATE_FORKPTY
1565 #include <grp.h>
1567 static int ptym_open (char *pts_name);
1568 static int ptys_open (int fdm, char * pts_name);
1571 login_tty(int ttyfd)
1573 int fd;
1574 char *fdname;
1576 #ifdef HAVE_SETSID
1577 setsid();
1578 #endif
1579 #ifdef HAVE_SETPGID
1580 setpgid(0, 0);
1581 #endif
1583 /* First disconnect from the old controlling tty. */
1584 #ifdef TIOCNOTTY
1585 fd = open("/dev/tty", O_RDWR|O_NOCTTY);
1586 if (fd >= 0)
1588 ioctl(fd, TIOCNOTTY, NULL);
1589 close(fd);
1591 else
1592 //syslog(LOG_WARNING, "NO CTTY");
1593 #endif /* TIOCNOTTY */
1595 /* Verify that we are successfully disconnected from the controlling tty. */
1596 fd = open("/dev/tty", O_RDWR|O_NOCTTY);
1597 if (fd >= 0)
1599 //syslog(LOG_WARNING, "Failed to disconnect from controlling tty.");
1600 close(fd);
1603 /* Make it our controlling tty. */
1604 #ifdef TIOCSCTTY
1605 ioctl(ttyfd, TIOCSCTTY, NULL);
1606 #endif /* TIOCSCTTY */
1608 fdname = ttyname (ttyfd);
1609 fd = open(fdname, O_RDWR);
1610 if (fd < 0)
1611 ;//syslog(LOG_WARNING, "open %s: %s", fdname, strerror(errno));
1612 else
1613 close(fd);
1615 /* Verify that we now have a controlling tty. */
1616 fd = open("/dev/tty", O_WRONLY);
1617 if (fd < 0)
1619 //syslog(LOG_WARNING, "open /dev/tty: %s", strerror(errno));
1620 return 1;
1623 close(fd);
1624 #if defined(HAVE_VHANGUP) && !defined(HAVE_REVOKE)
1626 RETSIGTYPE (*sig)();
1627 sig = signal(SIGHUP, SIG_IGN);
1628 vhangup();
1629 signal(SIGHUP, sig);
1631 #endif
1632 fd = open(fdname, O_RDWR);
1633 if (fd == -1)
1635 //syslog(LOG_ERR, "can't reopen ctty %s: %s", fdname, strerror(errno));
1636 return -1;
1639 close(ttyfd);
1641 if (fd != 0)
1642 close(0);
1643 if (fd != 1)
1644 close(1);
1645 if (fd != 2)
1646 close(2);
1648 dup2(fd, 0);
1649 dup2(fd, 1);
1650 dup2(fd, 2);
1651 if (fd > 2)
1652 close(fd);
1653 return 0;
1657 openpty(int *amaster, int *aslave, char *name, struct termios *termp,
1658 struct winsize *winp)
1660 char line[20];
1661 *amaster = ptym_open(line);
1662 if (*amaster < 0)
1663 return -1;
1664 *aslave = ptys_open(*amaster, line);
1665 if (*aslave < 0) {
1666 close(*amaster);
1667 return -1;
1669 if (name)
1670 strcpy(name, line);
1671 #ifndef TCSAFLUSH
1672 #define TCSAFLUSH TCSETAF
1673 #endif
1674 if (termp)
1675 (void) tcsetattr(*aslave, TCSAFLUSH, termp);
1676 #ifdef TIOCSWINSZ
1677 if (winp)
1678 (void) ioctl(*aslave, TIOCSWINSZ, (char *)winp);
1679 #endif
1680 return 0;
1683 static int
1684 ptym_open(char * pts_name)
1686 int fdm;
1687 #ifdef HAVE_PTSNAME
1688 char *ptr;
1690 strcpy(pts_name, "/dev/ptmx");
1691 fdm = open(pts_name, O_RDWR);
1692 if (fdm < 0)
1693 return -1;
1694 if (grantpt(fdm) < 0) { /* grant access to slave */
1695 close(fdm);
1696 return -2;
1698 if (unlockpt(fdm) < 0) { /* clear slave's lock flag */
1699 close(fdm);
1700 return -3;
1702 ptr = ptsname(fdm);
1703 if (ptr == NULL) { /* get slave's name */
1704 close (fdm);
1705 return -4;
1707 strcpy(pts_name, ptr); /* return name of slave */
1708 return fdm; /* return fd of master */
1709 #else
1710 char *ptr1, *ptr2;
1712 strcpy(pts_name, "/dev/ptyXY");
1713 /* array index: 012345689 (for references in following code) */
1714 for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1 != 0; ptr1++) {
1715 pts_name[8] = *ptr1;
1716 for (ptr2 = "0123456789abcdef"; *ptr2 != 0; ptr2++) {
1717 pts_name[9] = *ptr2;
1718 /* try to open master */
1719 fdm = open(pts_name, O_RDWR);
1720 if (fdm < 0) {
1721 if (errno == ENOENT) /* different from EIO */
1722 return -1; /* out of pty devices */
1723 else
1724 continue; /* try next pty device */
1726 pts_name[5] = 't'; /* chage "pty" to "tty" */
1727 return fdm; /* got it, return fd of master */
1730 return -1; /* out of pty devices */
1731 #endif
1734 static int
1735 ptys_open(int fdm, char * pts_name)
1737 int fds;
1738 #ifdef HAVE_PTSNAME
1739 /* following should allocate controlling terminal */
1740 fds = open(pts_name, O_RDWR);
1741 if (fds < 0) {
1742 close(fdm);
1743 return -5;
1745 if (ioctl(fds, I_PUSH, "ptem") < 0) {
1746 close(fdm);
1747 close(fds);
1748 return -6;
1750 if (ioctl(fds, I_PUSH, "ldterm") < 0) {
1751 close(fdm);
1752 close(fds);
1753 return -7;
1755 if (ioctl(fds, I_PUSH, "ttcompat") < 0) {
1756 close(fdm);
1757 close(fds);
1758 return -8;
1761 if (ioctl(fdm, I_PUSH, "pckt") < 0) {
1762 close(fdm);
1763 close(fds);
1764 return -8;
1767 if (ioctl(fdm, I_SRDOPT, RMSGN|RPROTDAT) < 0) {
1768 close(fdm);
1769 close(fds);
1770 return -8;
1773 return fds;
1774 #else
1775 int gid;
1776 struct group *grptr;
1778 grptr = getgrnam("tty");
1779 if (grptr != NULL)
1780 gid = grptr->gr_gid;
1781 else
1782 gid = -1; /* group tty is not in the group file */
1783 /* following two functions don't work unless we're root */
1784 chown(pts_name, getuid(), gid);
1785 chmod(pts_name, S_IRUSR | S_IWUSR | S_IWGRP);
1786 fds = open(pts_name, O_RDWR);
1787 if (fds < 0) {
1788 close(fdm);
1789 return -1;
1791 return fds;
1792 #endif
1796 forkpty(int *amaster, char *name, struct termios *termp, struct winsize *winp)
1798 int master, slave, pid;
1800 if (openpty(&master, &slave, name, termp, winp) == -1)
1801 return (-1);
1802 switch (pid = fork()) {
1803 case -1:
1804 return (-1);
1805 case 0:
1807 * child
1809 close(master);
1810 login_tty(slave);
1811 return (0);
1814 * parent
1816 *amaster = master;
1817 close(slave);
1818 return (pid);
1821 int scandir(const char *dir, struct dirent ***namelist,
1822 int (*select)(const struct dirent *),
1823 int (*compar)(const struct dirent **, const struct dirent **))
1825 DIR *d;
1826 struct dirent *entry;
1827 register int i=0;
1828 size_t entrysize;
1830 if ((d=opendir(dir)) == NULL)
1831 return(-1);
1833 *namelist=NULL;
1834 while ((entry=readdir(d)) != NULL)
1836 if (select == NULL || (select != NULL && (*select)(entry)))
1838 *namelist=(struct dirent **)realloc((void *)(*namelist),
1839 (size_t)((i+1)*sizeof(struct dirent *)));
1840 if (*namelist == NULL) return(-1);
1841 entrysize=sizeof(struct dirent)-sizeof(entry->d_name)+strlen(entry->d_name)+1;
1842 (*namelist)[i]=(struct dirent *)malloc(entrysize);
1843 if ((*namelist)[i] == NULL) return(-1);
1844 memcpy((*namelist)[i], entry, entrysize);
1845 i++;
1848 if (closedir(d)) return(-1);
1849 if (i == 0) return(-1);
1850 if (compar != NULL)
1851 qsort((void *)(*namelist), (size_t)i, sizeof(struct dirent *), compar);
1853 return(i);
1856 #endif /* EMULATE_FORKPTY */
1858 void
1859 anjuta_util_help_display (GtkWidget *parent,
1860 const gchar *doc_id,
1861 const gchar *item)
1863 GError *error = NULL;
1864 gchar *command;
1867 command = g_strdup_printf ("yelp ghelp:%s%s%s",
1868 doc_id,
1869 item == NULL ? "" : "?",
1870 item == NULL ? "" : item);
1872 if (!g_spawn_command_line_async (command, &error) &&
1873 (error != NULL))
1875 g_warning ("Error executing help application: %s",
1876 error->message);
1877 g_error_free (error);
1879 g_free (command);
1883 /* The following functions are taken from gedit */
1885 /* Note that this function replace home dir with ~ */
1886 gchar *
1887 anjuta_util_uri_get_dirname (const gchar *uri)
1889 gchar *res;
1890 gchar *str;
1892 // CHECK: does it work with uri chaining? - Paolo
1893 str = g_path_get_dirname (uri);
1894 g_return_val_if_fail (str != NULL, ".");
1896 if ((strlen (str) == 1) && (*str == '.'))
1898 g_free (str);
1900 return NULL;
1903 res = anjuta_util_replace_home_dir_with_tilde (str);
1905 g_free (str);
1907 return res;
1910 gchar*
1911 anjuta_util_replace_home_dir_with_tilde (const gchar *uri)
1913 gchar *tmp;
1914 gchar *home;
1916 g_return_val_if_fail (uri != NULL, NULL);
1918 /* Note that g_get_home_dir returns a const string */
1919 tmp = (gchar *)g_get_home_dir ();
1921 if (tmp == NULL)
1922 return g_strdup (uri);
1924 home = g_filename_to_utf8 (tmp, -1, NULL, NULL, NULL);
1925 if (home == NULL)
1926 return g_strdup (uri);
1928 if (strcmp (uri, home) == 0)
1930 g_free (home);
1932 return g_strdup ("~");
1935 tmp = home;
1936 home = g_strdup_printf ("%s/", tmp);
1937 g_free (tmp);
1939 if (g_str_has_prefix (uri, home))
1941 gchar *res;
1943 res = g_strdup_printf ("~/%s", uri + strlen (home));
1945 g_free (home);
1947 return res;
1950 g_free (home);
1952 return g_strdup (uri);
1956 * anjuta_util_shell_expand:
1957 * @string: input string
1959 * Expand environment variables $(var_name) and tilde (~) in the input string.
1961 * Returns: a newly-allocated string that must be freed with g_free().
1963 gchar*
1964 anjuta_util_shell_expand (const gchar *string)
1966 GString* expand;
1968 if (string == NULL) return NULL;
1970 expand = g_string_sized_new (strlen (string));
1972 for (; *string != '\0'; string++)
1974 switch (*string)
1976 case '$':
1978 /* Variable expansion */
1979 const gchar *end;
1980 gint var_name_len;
1982 end = string + 1;
1983 while (isalnum (*end) || (*end == '_')) end++;
1984 var_name_len = end - string - 1;
1985 if (var_name_len > 0)
1987 const gchar *value;
1989 g_string_append_len (expand, string + 1, var_name_len);
1990 value = g_getenv (expand->str + expand->len - var_name_len);
1991 g_string_truncate (expand, expand->len - var_name_len);
1992 g_string_append (expand, value);
1993 string = end - 1;
1994 continue;
1996 break;
1998 case '~':
2000 /* User home directory expansion */
2001 if (isspace(string[1]) || (string[1] == G_DIR_SEPARATOR) || (string[1] == '\0'))
2003 g_string_append (expand, g_get_home_dir());
2004 continue;
2006 break;
2008 default:
2009 break;
2011 g_string_append_c (expand, *string);
2014 return g_string_free (expand, FALSE);
2017 gchar *
2018 anjuta_util_str_middle_truncate (const gchar *string,
2019 guint truncate_length)
2021 GString *truncated;
2022 guint length;
2023 guint n_chars;
2024 guint num_left_chars;
2025 guint right_offset;
2026 guint delimiter_length;
2027 const gchar *delimiter = "\342\200\246";
2029 g_return_val_if_fail (string != NULL, NULL);
2031 length = strlen (string);
2033 g_return_val_if_fail (g_utf8_validate (string, length, NULL), NULL);
2035 /* It doesnt make sense to truncate strings to less than
2036 * the size of the delimiter plus 2 characters (one on each
2037 * side)
2039 delimiter_length = g_utf8_strlen (delimiter, -1);
2040 if (truncate_length < (delimiter_length + 2)) {
2041 return g_strdup (string);
2044 n_chars = g_utf8_strlen (string, length);
2046 /* Make sure the string is not already small enough. */
2047 if (n_chars <= truncate_length) {
2048 return g_strdup (string);
2051 /* Find the 'middle' where the truncation will occur. */
2052 num_left_chars = (truncate_length - delimiter_length) / 2;
2053 right_offset = n_chars - truncate_length + num_left_chars + delimiter_length;
2055 truncated = g_string_new_len (string,
2056 g_utf8_offset_to_pointer (string, num_left_chars) - string);
2057 g_string_append (truncated, delimiter);
2058 g_string_append (truncated, g_utf8_offset_to_pointer (string, right_offset));
2060 return g_string_free (truncated, FALSE);
2064 * Functions to implement XDG Base Directory Specification
2065 * http://standards.freedesktop.org/basedir-spec/latest/index.html
2066 * Use this to save any config/cache/data files
2070 static gchar*
2071 anjuta_util_construct_pathv (const gchar* str, va_list str_list)
2073 GPtrArray *str_arr;
2074 const gchar* tmp_str;
2075 gchar* path;
2077 str_arr = g_ptr_array_new();
2078 g_ptr_array_add (str_arr, (gpointer) str);
2080 /* Extract elements from va_list */
2081 if (str != NULL)
2083 while ((tmp_str = va_arg (str_list, const gchar*)) != NULL)
2085 g_ptr_array_add (str_arr, (gpointer)tmp_str);
2087 va_end (str_list);
2090 /* Terminate the list */
2091 g_ptr_array_add (str_arr, NULL);
2093 path = g_build_filenamev ((gchar **)str_arr->pdata);
2094 g_ptr_array_free (str_arr, TRUE);
2096 return path;
2099 static GFile*
2100 anjuta_util_get_user_cache_filev (const gchar* path, va_list list)
2102 gchar *uri_str, *base_path, *dir;
2103 GFile *uri;
2104 const gchar anjuta_prefix[] = "anjuta";
2105 base_path = g_build_filename (g_get_user_cache_dir(), anjuta_prefix, path, NULL);
2107 uri_str = anjuta_util_construct_pathv (base_path, list);
2108 g_free (base_path);
2110 uri = g_file_new_for_path (uri_str);
2111 dir = g_path_get_dirname (uri_str);
2112 g_free(uri_str);
2113 if (!anjuta_util_create_dir (dir)) return NULL;
2115 return uri;
2118 GFile*
2119 anjuta_util_get_user_cache_file (const gchar* path, ...)
2121 va_list list;
2122 va_start (list, path);
2123 return anjuta_util_get_user_cache_filev (path, list);
2126 static GFile*
2127 anjuta_util_get_user_config_filev (const gchar* path, va_list list)
2129 gchar *uri_str, *base_path, *dir;
2130 GFile *uri;
2131 const gchar anjuta_prefix[] = "anjuta";
2132 base_path = g_build_filename (g_get_user_config_dir(), anjuta_prefix, path, NULL);
2134 uri_str = anjuta_util_construct_pathv (base_path, list);
2135 g_free (base_path);
2137 uri = g_file_new_for_path (uri_str);
2138 dir = g_path_get_dirname (uri_str);
2139 g_free(uri_str);
2140 if (!anjuta_util_create_dir (dir)) return NULL;
2142 return uri;
2145 GFile*
2146 anjuta_util_get_user_config_file (const gchar* path, ...)
2148 va_list list;
2149 va_start (list, path);
2150 return anjuta_util_get_user_config_filev (path, list);
2153 static GFile*
2154 anjuta_util_get_user_data_filev (const gchar* path, va_list list)
2156 gchar *uri_str, *base_path, *dir;
2157 GFile *uri;
2158 const gchar anjuta_prefix[] = "anjuta";
2159 base_path = g_build_filename (g_get_user_data_dir(), anjuta_prefix, path, NULL);
2161 uri_str = anjuta_util_construct_pathv (base_path, list);
2162 g_free (base_path);
2164 uri = g_file_new_for_path (uri_str);
2165 dir = g_path_get_dirname (uri_str);
2166 g_free(uri_str);
2167 if (!anjuta_util_create_dir (dir)) return NULL;
2169 return uri;
2172 GFile*
2173 anjuta_util_get_user_data_file (const gchar* path, ...)
2175 va_list list;
2176 va_start (list, path);
2177 return anjuta_util_get_user_data_filev (path, list);
2180 gchar*
2181 anjuta_util_get_user_cache_file_path (const gchar* path, ...)
2183 va_list list;
2184 GFile *file;
2185 gchar *file_path;
2186 va_start (list, path);
2187 file = anjuta_util_get_user_cache_filev (path, list);
2188 file_path = g_file_get_path (file);
2189 g_object_unref (file);
2191 return file_path;
2194 gchar*
2195 anjuta_util_get_user_config_file_path (const gchar* path, ...)
2197 va_list list;
2198 GFile *file;
2199 gchar *file_path;
2200 va_start (list, path);
2201 file = anjuta_util_get_user_config_filev (path, list);
2202 file_path = g_file_get_path (file);
2203 g_object_unref (file);
2205 return file_path;
2208 gchar*
2209 anjuta_util_get_user_data_file_path (const gchar* path, ...)
2211 va_list list;
2212 GFile *file;
2213 gchar *file_path;;
2214 va_start (list, path);
2215 file = anjuta_util_get_user_data_filev (path, list);
2216 file_path = g_file_get_path (file);
2217 g_object_unref (file);
2219 return file_path;
2222 GList *
2223 anjuta_util_convert_gfile_list_to_path_list (GList *list)
2225 GList *path_list;
2226 GList *current_file;
2227 gchar *path;
2229 path_list = NULL;
2231 for (current_file = list; current_file != NULL; current_file = g_list_next (current_file))
2233 path = g_file_get_path (current_file->data);
2235 /* Ignore files with invalid paths */
2236 if (path)
2237 path_list = g_list_append (path_list, path);
2240 return path_list;
2243 GList *
2244 anjuta_util_convert_gfile_list_to_relative_path_list (GList *list,
2245 const gchar *parent)
2247 GFile *parent_file;
2248 GList *path_list;
2249 GList *current_file;
2250 gchar *path;
2252 parent_file = g_file_new_for_path (parent);
2253 path_list = NULL;
2255 if (parent_file)
2257 for (current_file = list; current_file != NULL; current_file = g_list_next (current_file))
2259 path = g_file_get_relative_path (parent_file, current_file->data);
2261 /* Ignore files with invalid paths */
2262 if (path)
2263 path_list = g_list_append (path_list, path);
2266 g_object_unref (parent_file);
2269 return path_list;
2274 * anjuta_util_builder_new:
2275 * @filename: Builder file name to open
2276 * @error: Optional error object, if NULL display a dialog if the file is missing
2278 * Create a new GtkBuilder object and load the file in it. Display an error
2279 * if the file is missing. Use a dialog if error is NULL, just a warning
2280 * if the error can be reported.
2282 * Returns: The new GtkBuilder object
2284 GtkBuilder *
2285 anjuta_util_builder_new (const gchar *filename, GError **error)
2287 GtkBuilder *bxml = gtk_builder_new ();
2288 GError *err = NULL;
2290 /* Load glade file */
2291 if (!gtk_builder_add_from_file (bxml, filename, &err))
2293 g_object_unref (bxml);
2294 bxml = NULL;
2296 /* Display the error to the user if it cannot be reported to the caller */
2297 if (error == NULL)
2299 anjuta_util_dialog_error (NULL, _("Unable to load user interface file: %s"), err->message);
2301 else
2303 g_warning ("Couldn't load builder file: %s", err->message);
2305 g_propagate_error (error, err);
2308 /* Tag the builder object with the filename to allow better error message
2309 * with the following function */
2310 if (bxml != NULL)
2312 g_object_set_data_full (G_OBJECT (bxml), "filename", g_strdup (filename), g_free);
2315 return bxml;
2319 * anjuta_util_builder_get_objects:
2320 * @builder: Builder object
2321 * @first_widget: Name of first widget to get
2322 * ...: Address to store the first widget pointer, followed optionally by
2323 * more name/pointer pairs, followed by NULL
2325 * Create a new GtkBuilder object and load the file in it. Display an error
2326 * if the file is missing. Use a dialog if error is NULL, just a warning
2327 * if the error can be reported.
2329 * Returns: TRUE is everything works as expected.
2331 gboolean
2332 anjuta_util_builder_get_objects (GtkBuilder *builder, const gchar *first_widget,...)
2334 va_list args;
2335 const gchar *name;
2336 GObject **object_ptr;
2337 gboolean missing = FALSE;
2339 va_start (args, first_widget);
2341 for (name = first_widget; name; name = va_arg (args, char *))
2343 object_ptr = va_arg (args, void *);
2344 *object_ptr = gtk_builder_get_object (builder, name);
2346 /* Object not found, display a warning */
2347 if (!*object_ptr)
2349 const gchar *filename = (const gchar *)g_object_get_data (G_OBJECT (builder), "filename");
2350 if (filename)
2352 g_warning ("Missing widget '%s' in file %s", name, filename);
2354 else
2356 g_warning("Missing widget '%s'", name);
2358 missing = TRUE;
2361 va_end (args);
2363 return !missing;
2367 * anjuta_utils_drop_get_files:
2368 * @selection_data: the #GtkSelectionData from drag_data_received
2369 * @info: the info from drag_data_received
2371 * Create a list of valid uri's from a uri-list drop.
2373 * Return value: a list of GFiles
2375 GSList*
2376 anjuta_utils_drop_get_files (GtkSelectionData *selection_data)
2378 gchar **uris;
2379 gint i;
2380 GSList* files = NULL;
2382 uris = g_uri_list_extract_uris ((gchar *) gtk_selection_data_get_data (selection_data));
2384 for (i = 0; uris[i] != NULL; i++)
2386 GFile* file = g_file_new_for_uri (uris[i]);
2387 files = g_slist_append(files, file);
2390 return files;
2394 * anjuta_util_get_user_mail:
2396 * Returns: The e-mail Address of the logged-in user. The resulting string
2397 * must be free'd after use.
2399 gchar*
2400 anjuta_util_get_user_mail()
2402 /* FIXME: Use libfolks or something like it to query the mail address */
2403 return g_strconcat(g_get_user_name (), "@", g_get_host_name (), NULL);
2407 * anjuta_utils_clone_string_gptrarray:
2408 * @source: The source GPtrArray containing items representing strings
2410 * Clones the contents of source GPtrArray into a new allocated GPtrArray.
2412 * Return a new allocated GPtrArray with strings g_strdup (), NULL on error.
2413 * The returned array has set g_free as GDestroyNotity function, so that user
2414 * should only care to g_ptr_array_unref () without freeing the strings.
2416 GPtrArray *
2417 anjuta_util_clone_string_gptrarray (const GPtrArray* source)
2419 gint i;
2420 GPtrArray *dest;
2422 g_return_val_if_fail (source != NULL, NULL);
2424 dest = g_ptr_array_sized_new (source->len);
2425 g_ptr_array_set_free_func (dest, g_free);
2427 for (i = 0; i < source->len; i++)
2429 g_ptr_array_add (dest, g_strdup (g_ptr_array_index (source, i)));
2432 return dest;
2435 void
2436 anjuta_util_list_all_dir_children (GList **children, GFile *dir)
2438 GFileEnumerator *list;
2440 list = g_file_enumerate_children (dir,
2441 G_FILE_ATTRIBUTE_STANDARD_NAME,
2442 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
2443 NULL,
2444 NULL);
2446 if (list != NULL)
2448 GFileInfo *info;
2450 while ((info = g_file_enumerator_next_file (list, NULL, NULL)) != NULL)
2452 const gchar *name;
2453 GFile *file;
2455 name = g_file_info_get_name (info);
2456 file = g_file_get_child (dir, name);
2457 g_object_unref (info);
2459 if (g_file_query_file_type (file, G_FILE_QUERY_INFO_NONE, NULL) == G_FILE_TYPE_DIRECTORY)
2461 anjuta_util_list_all_dir_children (children, file);
2462 g_object_unref (file);
2464 else
2466 *children = g_list_prepend (*children, file);
2469 g_file_enumerator_close (list, NULL, NULL);
2470 g_object_unref (list);
2474 GPtrArray *
2475 anjuta_util_convert_string_list_to_array (GList *list)
2477 GList *node;
2478 GPtrArray *res;
2480 g_return_val_if_fail (list != NULL, NULL);
2482 res = g_ptr_array_new_with_free_func (g_free);
2484 node = list;
2485 while (node != NULL)
2487 g_ptr_array_add (res, g_strdup (node->data));
2489 node = g_list_next (node);
2492 return res;