symbol-db: Get rid of useless queued-multi
[anjuta.git] / libanjuta / anjuta-utils.c
blobc9bb5d783cb57800e0e3e9e3c767681bb04aa94b
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>
5 *
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 <dbus/dbus-glib.h>
53 #include <glib/gi18n.h>
54 #include <glib.h>
55 #include <glib/gstdio.h>
56 #include <gtk/gtk.h>
58 #include <gconf/gconf-client.h>
60 #include <libanjuta/anjuta-utils.h>
61 #include <libanjuta/anjuta-debug.h>
63 #define FILE_BUFFER_SIZE 1024
65 static void
66 anjuta_util_from_file_to_file (GInputStream *istream,
67 GOutputStream *ostream)
69 gsize bytes = 1;
70 GError *error = NULL;
71 gchar buffer[FILE_BUFFER_SIZE];
73 while (bytes != 0 && bytes != -1)
75 bytes = g_input_stream_read (istream, buffer,
76 sizeof (buffer),
77 NULL, &error);
78 if (error)
79 break;
81 g_output_stream_write (ostream, buffer,
82 bytes,
83 NULL, &error);
84 if (error)
85 break;
88 if (error)
90 g_warning ("%s", error->message);
91 g_error_free (error);
92 error = NULL;
95 if (!g_output_stream_close (ostream, NULL, &error))
97 g_warning ("%s", error->message);
98 g_error_free (error);
99 error = NULL;
101 if (!g_input_stream_close (istream, NULL, &error))
103 g_warning ("%s", error->message);
104 g_error_free (error);
109 * anjuta_util_copy_file:
110 * @src: the file where copy
111 * @dest: the path to copy the @src
112 * @show_error: TRUE to show a dialog error
114 * Copies @src to @dest and shows a dialog error in case is needed.
116 * Returns: TRUE if there was an error copying the file.
118 gboolean
119 anjuta_util_copy_file (const gchar * src, const gchar * dest, gboolean show_error)
121 GFile *src_file, *dest_file;
122 GFileInputStream *istream;
123 GFileOutputStream *ostream;
124 GError *error = NULL;
125 gboolean toret = FALSE;
127 src_file = g_file_new_for_path (src);
128 dest_file = g_file_new_for_path (dest);
130 istream = g_file_read (src_file, NULL, &error);
131 if (error)
132 goto free;
134 ostream = g_file_create (dest_file, G_FILE_CREATE_NONE,
135 NULL, &error);
136 if (error)
137 goto free;
139 anjuta_util_from_file_to_file (G_INPUT_STREAM (istream), G_OUTPUT_STREAM (ostream));
141 free: if (error)
143 if (show_error)
144 anjuta_util_dialog_error_system (NULL, error->code,
145 error->message);
147 g_warning ("%s", error->message);
149 toret = TRUE;
152 g_object_unref (src_file);
153 g_object_unref (dest_file);
155 return toret;
158 void
159 anjuta_util_color_from_string (const gchar * val, guint16 * r, guint16 * g, guint16 * b)
161 GdkColor color;
162 if (gdk_color_parse(val, &color))
164 *r = color.red;
165 *g = color.green;
166 *b =color.blue;
170 gchar *
171 anjuta_util_string_from_color (guint16 r, guint16 g, guint16 b)
173 return g_strdup_printf("#%02x%02x%02x", r >> 8, g >> 8, b >> 8);
176 GtkWidget*
177 anjuta_util_button_new_with_stock_image (const gchar* text,
178 const gchar* stock_id)
180 GtkWidget *button;
181 GtkWidget *child;
182 GtkStockItem item;
183 GtkWidget *label;
184 GtkWidget *image;
185 GtkWidget *hbox;
186 GtkWidget *align;
188 button = gtk_button_new ();
190 child = gtk_bin_get_child (GTK_BIN (button));
191 if (child)
192 gtk_container_remove (GTK_CONTAINER (button), child);
194 if (gtk_stock_lookup (stock_id, &item))
196 label = gtk_label_new_with_mnemonic (text);
198 gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
200 image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON);
201 hbox = gtk_hbox_new (FALSE, 2);
203 align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
205 gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
206 gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
208 gtk_container_add (GTK_CONTAINER (button), align);
209 gtk_container_add (GTK_CONTAINER (align), hbox);
210 gtk_widget_show_all (align);
212 return button;
215 label = gtk_label_new_with_mnemonic (text);
216 gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
218 gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
220 gtk_widget_show (label);
221 gtk_container_add (GTK_CONTAINER (button), label);
223 return button;
226 GtkWidget*
227 anjuta_util_dialog_add_button (GtkDialog *dialog, const gchar* text,
228 const gchar* stock_id, gint response_id)
230 GtkWidget *button;
232 g_return_val_if_fail (GTK_IS_DIALOG (dialog), NULL);
233 g_return_val_if_fail (text != NULL, NULL);
234 g_return_val_if_fail (stock_id != NULL, NULL);
236 button = anjuta_util_button_new_with_stock_image (text, stock_id);
237 g_return_val_if_fail (button != NULL, NULL);
239 gtk_widget_set_can_default (button, TRUE);
241 gtk_widget_show (button);
243 gtk_dialog_add_action_widget (dialog, button, response_id);
245 return button;
248 void
249 anjuta_util_dialog_error (GtkWindow *parent, const gchar *mesg, ...)
251 gchar* message;
252 va_list args;
253 GtkWidget *dialog;
254 GtkWindow *real_parent;
256 va_start (args, mesg);
257 message = g_strdup_vprintf (mesg, args);
258 va_end (args);
260 if (parent && GTK_IS_WINDOW (parent))
262 real_parent = parent;
264 else
266 real_parent = NULL;
269 // Dialog to be HIG compliant
270 dialog = gtk_message_dialog_new (real_parent,
271 GTK_DIALOG_DESTROY_WITH_PARENT,
272 GTK_MESSAGE_ERROR,
273 GTK_BUTTONS_CLOSE, "%s", message);
274 g_signal_connect (G_OBJECT (dialog), "response",
275 G_CALLBACK (gtk_widget_destroy), NULL);
276 gtk_widget_show (dialog);
277 g_free (message);
280 void
281 anjuta_util_dialog_warning (GtkWindow *parent, const gchar * mesg, ...)
283 gchar* message;
284 va_list args;
285 GtkWidget *dialog;
286 GtkWindow *real_parent;
288 va_start (args, mesg);
289 message = g_strdup_vprintf (mesg, args);
290 va_end (args);
292 if (parent && GTK_IS_WINDOW (parent))
294 real_parent = parent;
296 else
298 real_parent = NULL;
301 // Dialog to be HIG compliant
302 dialog = gtk_message_dialog_new (real_parent,
303 GTK_DIALOG_DESTROY_WITH_PARENT,
304 GTK_MESSAGE_WARNING,
305 GTK_BUTTONS_CLOSE, "%s", message);
306 g_signal_connect (G_OBJECT (dialog), "response",
307 G_CALLBACK (gtk_widget_destroy), NULL);
308 gtk_widget_show (dialog);
309 g_free (message);
312 void
313 anjuta_util_dialog_info (GtkWindow *parent, const gchar * mesg, ...)
315 gchar* message;
316 va_list args;
317 GtkWidget *dialog;
318 GtkWindow *real_parent;
320 va_start (args, mesg);
321 message = g_strdup_vprintf (mesg, args);
322 va_end (args);
324 if (parent && GTK_IS_WINDOW (parent))
326 real_parent = parent;
328 else
330 real_parent = NULL;
332 // Dialog to be HIG compliant
333 dialog = gtk_message_dialog_new (real_parent,
334 GTK_DIALOG_DESTROY_WITH_PARENT,
335 GTK_MESSAGE_INFO,
336 GTK_BUTTONS_CLOSE, "%s", message);
337 g_signal_connect (G_OBJECT (dialog), "response",
338 G_CALLBACK (gtk_widget_destroy), NULL);
339 gtk_widget_show (dialog);
340 g_free (message);
343 void
344 anjuta_util_dialog_error_system (GtkWindow* parent, gint errnum,
345 const gchar * mesg, ... )
347 gchar* message;
348 gchar* tot_mesg;
349 va_list args;
350 GtkWidget *dialog;
351 GtkWindow *real_parent;
353 va_start (args, mesg);
354 message = g_strdup_vprintf (mesg, args);
355 va_end (args);
357 if (0 != errnum) {
358 /* Avoid space in translated string */
359 tot_mesg = g_strconcat (message, "\n", _("System:"), " ",
360 g_strerror(errnum), NULL);
361 g_free (message);
362 } else
363 tot_mesg = message;
365 if (parent && GTK_IS_WINDOW (parent))
367 real_parent = parent;
369 else
371 real_parent = NULL;
373 // Dialog to be HIG compliant
374 dialog = gtk_message_dialog_new (real_parent,
375 GTK_DIALOG_DESTROY_WITH_PARENT,
376 GTK_MESSAGE_ERROR,
377 GTK_BUTTONS_CLOSE, "%s", tot_mesg);
378 g_signal_connect (G_OBJECT (dialog), "response",
379 G_CALLBACK (gtk_widget_destroy), NULL);
380 gtk_widget_show (dialog);
381 g_free (tot_mesg);
384 gboolean
385 anjuta_util_dialog_boolean_question (GtkWindow *parent, const gchar *mesg, ...)
387 gchar* message;
388 va_list args;
389 GtkWidget *dialog;
390 gint ret;
391 GtkWindow *real_parent;
393 va_start (args, mesg);
394 message = g_strdup_vprintf (mesg, args);
395 va_end (args);
397 if (parent && GTK_IS_WINDOW (parent))
399 real_parent = parent;
401 else
403 real_parent = NULL;
406 dialog = gtk_message_dialog_new (real_parent,
407 GTK_DIALOG_DESTROY_WITH_PARENT,
408 GTK_MESSAGE_QUESTION,
409 GTK_BUTTONS_YES_NO, "%s", message);
411 ret = gtk_dialog_run (GTK_DIALOG (dialog));
412 gtk_widget_destroy (dialog);
413 g_free (message);
415 return (ret == GTK_RESPONSE_YES);
418 gboolean
419 anjuta_util_dialog_input (GtkWindow *parent, const gchar *prompt,
420 const gchar *default_value, gchar **return_value)
422 GtkWidget *dialog, *label, *frame, *entry, *dialog_vbox, *vbox;
423 gint res;
424 gchar *markup;
425 GtkWindow *real_parent;
427 if (parent && GTK_IS_WINDOW (parent))
429 real_parent = parent;
431 else
433 real_parent = NULL;
436 dialog = gtk_dialog_new_with_buttons (prompt, real_parent,
437 GTK_DIALOG_DESTROY_WITH_PARENT,
438 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
439 GTK_STOCK_OK, GTK_RESPONSE_OK,
440 NULL);
441 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
442 dialog_vbox = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
443 gtk_window_set_default_size (GTK_WINDOW (dialog), 400, -1);
444 gtk_widget_show (dialog_vbox);
446 markup = g_strconcat ("<b>", prompt, "</b>", NULL);
447 label = gtk_label_new (NULL);
448 gtk_label_set_markup (GTK_LABEL (label), markup);
449 gtk_widget_show (label);
450 g_free (markup);
452 frame = gtk_frame_new (NULL);
453 gtk_frame_set_label_widget (GTK_FRAME (frame), label);
454 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
455 gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
456 gtk_widget_show (frame);
457 gtk_box_pack_start (GTK_BOX (dialog_vbox), frame, FALSE, FALSE, 0);
459 vbox = gtk_vbox_new (FALSE, 0);
460 gtk_widget_show (vbox);
461 gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
462 gtk_container_add (GTK_CONTAINER (frame), vbox);
464 entry = gtk_entry_new ();
465 gtk_widget_show (entry);
466 gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
467 gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
468 if (default_value)
469 gtk_entry_set_text (GTK_ENTRY (entry), default_value);
471 res = gtk_dialog_run (GTK_DIALOG (dialog));
473 if (gtk_entry_get_text (GTK_ENTRY (entry)) &&
474 strlen (gtk_entry_get_text (GTK_ENTRY (entry))) > 0)
476 *return_value = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
478 else
480 *return_value = NULL;
482 gtk_widget_destroy (dialog);
483 return (res == GTK_RESPONSE_OK);
486 static void
487 on_install_files_done (DBusGProxy *proxy, DBusGProxyCall *call_id,
488 gpointer user_data)
490 GError *error = NULL;
491 dbus_g_proxy_end_call (proxy, call_id, &error, G_TYPE_INVALID);
492 if (error)
495 Only dbus error is handled. Rest of the errors are from packagekit
496 which have already been notified to user by packagekit.
498 if (error->domain == DBUS_GERROR)
500 const gchar *error_message = NULL;
502 /* Service error which implies packagekit is missing */
503 if (error->code == DBUS_GERROR_SERVICE_UNKNOWN)
505 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.");
507 /* General dbus error implies failure to call dbus method */
508 else if (error->code != DBUS_GERROR_REMOTE_EXCEPTION &&
509 error->code != DBUS_GERROR_NO_REPLY)
511 error_message = error->message;
513 if (error_message)
514 anjuta_util_dialog_error (NULL,
515 _("Installation failed: %s"),
516 error_message);
518 g_error_free (error);
522 gboolean
523 anjuta_util_install_files (const gchar * const names)
525 DBusGConnection * connection;
526 DBusGProxy * proxy;
527 guint32 xid = 0;
528 gchar ** pkgv;
530 if (!names)
531 return FALSE;
533 connection = dbus_g_bus_get (DBUS_BUS_SESSION, NULL);
534 if (!connection)
535 return FALSE;
537 proxy = dbus_g_proxy_new_for_name (connection,
538 "org.freedesktop.PackageKit",
539 "/org/freedesktop/PackageKit",
540 "org.freedesktop.PackageKit.Modify");
541 if (!proxy)
542 return FALSE;
544 pkgv = g_strsplit (names, ", ", 0);
545 dbus_g_proxy_begin_call (proxy, "InstallProvideFiles",
546 on_install_files_done, NULL, NULL,
547 G_TYPE_UINT, xid,
548 G_TYPE_STRV, pkgv,
549 G_TYPE_STRING, "",
550 G_TYPE_INVALID, G_TYPE_INVALID);
551 g_strfreev (pkgv);
552 return TRUE;
555 gboolean
556 anjuta_util_package_is_installed (const gchar * package, gboolean show)
558 gboolean installed = FALSE;
559 int status;
560 int exit_status;
561 pid_t pid;
563 if ((pid = fork()) == 0)
564 execlp ("pkg-config", "pkg-config", "--exists", package, NULL);
566 waitpid (pid, &status, 0);
567 exit_status = WEXITSTATUS (status);
568 installed = (exit_status == 0) ? TRUE : FALSE;
569 if (installed)
570 return TRUE;
572 if (show)
574 anjuta_util_dialog_error (NULL,
575 _("The \"%s\" package is not installed.\n"
576 "Please install it."), package);
579 return FALSE;
582 gboolean
583 anjuta_util_prog_is_installed (const gchar * prog, gboolean show)
585 gchar* prog_path = g_find_program_in_path (prog);
586 if (prog_path)
588 g_free (prog_path);
589 return TRUE;
591 if (show)
593 anjuta_util_dialog_error (NULL, _("The \"%s\" utility is not installed.\n"
594 "Please install it."), prog);
596 return FALSE;
599 gchar *
600 anjuta_util_get_a_tmp_file (void)
602 static gint count = 0;
603 gchar *filename;
604 const gchar *tmpdir;
606 tmpdir = g_get_tmp_dir ();
607 filename =
608 g_strdup_printf ("%s/anjuta_%d.%d", tmpdir, count++, getpid ());
609 return filename;
612 /* GList of strings operations */
613 GList *
614 anjuta_util_glist_from_string (const gchar *string)
616 gchar *str, *temp, buff[256];
617 GList *list;
618 gchar *word_start, *word_end;
619 gboolean the_end;
621 list = NULL;
622 the_end = FALSE;
623 temp = g_strdup (string);
624 str = temp;
625 if (!str)
626 return NULL;
628 while (1)
630 gint i;
631 gchar *ptr;
633 /* Remove leading spaces */
634 while (isspace (*str) && *str != '\0')
635 str++;
636 if (*str == '\0')
637 break;
639 /* Find start and end of word */
640 word_start = str;
641 while (!isspace (*str) && *str != '\0')
642 str++;
643 word_end = str;
645 /* Copy the word into the buffer */
646 for (ptr = word_start, i = 0; ptr < word_end; ptr++, i++)
647 buff[i] = *ptr;
648 buff[i] = '\0';
649 if (strlen (buff))
650 list = g_list_append (list, g_strdup (buff));
651 if (*str == '\0')
652 break;
654 if (temp)
655 g_free (temp);
656 return list;
659 /* Prefix the strings */
660 void
661 anjuta_util_glist_strings_prefix (GList * list, const gchar *prefix)
663 GList *node;
664 node = list;
666 g_return_if_fail (prefix != NULL);
667 while (node)
669 gchar* tmp;
670 tmp = node->data;
671 node->data = g_strconcat (prefix, tmp, NULL);
672 if (tmp) g_free (tmp);
673 node = g_list_next (node);
677 /* Suffix the strings */
678 void
679 anjuta_util_glist_strings_sufix (GList * list, const gchar *sufix)
681 GList *node;
682 node = list;
684 g_return_if_fail (sufix != NULL);
685 while (node)
687 gchar* tmp;
688 tmp = node->data;
689 node->data = g_strconcat (tmp, sufix, NULL);
690 if (tmp) g_free (tmp);
691 node = g_list_next (node);
695 /* Duplicate list of strings */
696 GList*
697 anjuta_util_glist_strings_dup (GList * list)
699 GList *node;
700 GList *new_list;
702 new_list = NULL;
703 node = list;
704 while (node)
706 if (node->data)
707 new_list = g_list_append (new_list, g_strdup(node->data));
708 else
709 new_list = g_list_append (new_list, NULL);
710 node = g_list_next (node);
712 return new_list;
715 /* Join list of strings using the given delimiter */
716 gchar*
717 anjuta_util_glist_strings_join (GList * list, gchar *delimiter)
719 GString *joined;
720 gboolean first = TRUE;
721 GList *node;
723 joined = g_string_new (NULL);
724 node = list;
725 while (node)
727 if (node->data)
729 if (!first)
730 g_string_append (joined, delimiter);
731 else
732 first = FALSE;
733 g_string_append (joined, node->data);
735 node = g_list_next (node);
737 if (joined->len > 0)
738 return g_string_free (joined, FALSE);
739 else
740 g_string_free (joined, TRUE);
741 return NULL;
744 gchar*
745 anjuta_util_get_real_path (const gchar *path)
747 if (path != NULL)
749 gchar *result;
750 #ifdef PATH_MAX
751 gchar buf[PATH_MAX+1];
753 result = realpath (path, buf);
754 if (result != NULL)
756 *(buf + PATH_MAX) = '\0'; /* ensure a terminator */
757 return g_strdup (buf);
759 #else
760 char *buf;
761 /* the string returned by realpath should be cleaned with
762 free(), not g_free() */
763 buf = realpath (path, NULL);
764 if (buf != NULL)
766 result = g_strdup (buf);
767 free (buf);
768 return result;
770 #endif
772 return NULL;
776 * anjuta_util_get_current_dir:
778 * Get current working directory, unlike g_get_current_dir, keeps symbolic links
779 * in path name.
781 * Returns: The current working directory.
783 gchar*
784 anjuta_util_get_current_dir (void)
786 const gchar *pwd;
788 pwd = g_getenv ("PWD");
789 if (pwd != NULL)
791 return g_strdup (pwd);
793 else
795 return g_get_current_dir ();
799 static gboolean
800 is_valid_scheme_character (char c)
802 return g_ascii_isalnum (c) || c == '+' || c == '-' || c == '.';
805 /* Following RFC 2396, valid schemes are built like:
806 * scheme = alpha *( alpha | digit | "+" | "-" | "." )
808 static gboolean
809 has_valid_scheme (const char *uri)
811 const char *p;
813 p = uri;
815 if (!g_ascii_isalpha (*p))
816 return FALSE;
818 do {
819 p++;
820 } while (is_valid_scheme_character (*p));
822 return *p == ':';
826 * anjuta_util_file_new_for_commandline_arg:
828 * @arg: URI or relative or absolute file path
830 * Create a new file corresponding to arg, unlike g_file_new_for_commandline_arg,
831 * keeps symbolic links in path name.
833 * Returns: A new GFile object
835 GFile *
836 anjuta_util_file_new_for_commandline_arg (const gchar *arg)
838 GFile *file;
839 char *filename;
840 char *current_dir;
842 g_return_val_if_fail (arg != NULL, NULL);
844 if (g_path_is_absolute (arg))
845 return g_file_new_for_path (arg);
847 if (has_valid_scheme (arg))
848 return g_file_new_for_uri (arg);
850 current_dir = anjuta_util_get_current_dir ();
851 filename = g_build_filename (current_dir, arg, NULL);
852 g_free (current_dir);
854 file = g_file_new_for_path (filename);
855 g_free (filename);
857 return file;
861 /* Dedup a list of paths - duplicates are removed from the tail.
862 ** Useful for deduping Recent Files and Recent Projects */
863 GList*
864 anjuta_util_glist_path_dedup(GList *list)
866 GList *nlist = NULL, *tmp, *tmp1;
867 gchar *path;
868 struct stat s;
869 for (tmp = list; tmp; tmp = g_list_next(tmp))
871 path = anjuta_util_get_real_path ((const gchar *) tmp->data);
872 if (path)
874 if (stat (path, &s) != 0)
876 g_free(path);
878 else
880 for (tmp1 = nlist; tmp1; tmp1 = g_list_next(tmp1))
882 if (0 == strcmp((const char *) tmp1->data, path))
884 g_free(path);
885 path = NULL;
886 break;
889 if (path)
890 nlist = g_list_prepend(nlist, path);
894 anjuta_util_glist_strings_free(list);
895 nlist = g_list_reverse(nlist);
896 return nlist;
899 static gint
900 sort_node (gchar* a, gchar *b)
902 if ( !a && !b) return 0;
903 else if (!a) return -1;
904 else if (!b) return 1;
905 return strcmp (a, b);
908 /* Sort the list alphabatically */
909 GList*
910 anjuta_util_glist_strings_sort (GList * list)
912 return g_list_sort(list, (GCompareFunc)sort_node);
915 /* Free the strings and GList */
916 void
917 anjuta_util_glist_strings_free (GList * list)
919 GList *node;
920 node = list;
921 while (node)
923 if (node->data)
924 g_free (node->data);
925 node = g_list_next (node);
927 g_list_free (list);
931 anjuta_util_type_from_string (AnjutaUtilStringMap *map, const char *str)
933 int i = 0;
935 while (-1 != map[i].type)
937 if (0 == strcmp(map[i].name, str))
938 return map[i].type;
939 ++ i;
941 return -1;
944 const char*
945 anjuta_util_string_from_type (AnjutaUtilStringMap *map, int type)
947 int i = 0;
948 while (-1 != map[i].type)
950 if (map[i].type == type)
951 return map[i].name;
952 ++ i;
954 return "";
957 GList*
958 anjuta_util_glist_from_map (AnjutaUtilStringMap *map)
960 GList *out_list = NULL;
961 int i = 0;
962 while (-1 != map[i].type)
964 out_list = g_list_append(out_list, map[i].name);
965 ++ i;
967 return out_list;
971 GList *
972 anjuta_util_update_string_list (GList *p_list, const gchar *p_str, gint length)
974 gint i;
975 gchar *str;
976 if (!p_str)
977 return p_list;
978 for (i = 0; i < g_list_length (p_list); i++)
980 str = (gchar *) g_list_nth_data (p_list, i);
981 if (!str)
982 continue;
983 if (strcmp (p_str, str) == 0)
985 p_list = g_list_remove (p_list, str);
986 p_list = g_list_prepend (p_list, str);
987 return p_list;
990 p_list = g_list_prepend (p_list, g_strdup (p_str));
991 while (g_list_length (p_list) > length)
993 str = g_list_nth_data (p_list, g_list_length (p_list) - 1);
994 p_list = g_list_remove (p_list, str);
995 g_free (str);
997 return p_list;
1000 gboolean
1001 anjuta_util_create_dir (const gchar* path)
1003 GFile *dir = g_file_new_for_path (path);
1004 GError *err = NULL;
1005 gchar *parent;
1007 if (g_file_query_exists (dir, NULL))
1009 GFileInfo *info = g_file_query_info (dir,
1010 G_FILE_ATTRIBUTE_STANDARD_TYPE,
1011 G_FILE_QUERY_INFO_NONE,
1012 NULL, NULL);
1013 if (g_file_info_get_file_type (info) != G_FILE_TYPE_DIRECTORY)
1015 g_message ("Warning: %s is a file. \n \
1016 It is trying to be treated as a directory.",g_file_get_path (dir));
1017 g_object_unref (dir);
1018 return FALSE;
1020 g_object_unref (info);
1022 else
1024 parent = g_path_get_dirname (path);
1025 if (anjuta_util_create_dir (parent))
1027 g_free (parent);
1028 if (!g_file_make_directory (dir, NULL, &err))
1030 g_warning ("Error directory:\n %s", err->message);
1031 g_object_unref (dir);
1032 return FALSE;
1035 else
1037 g_free (parent);
1038 g_object_unref (dir);
1039 return FALSE;
1042 g_object_unref (dir);
1044 return TRUE;
1048 * anjuta_util_user_shell:
1050 * Retrieves the user's preferred shell.
1052 * Returns: A newly allocated string that is the path to the shell.
1054 /* copied from deprecated gnome_util_user_shell in libgnome */
1055 gchar *
1056 anjuta_util_user_shell (void)
1058 #ifndef G_OS_WIN32
1059 struct passwd *pw;
1060 gint i;
1061 const gchar *shell;
1062 const gchar shells [][14] = {
1063 /* Note that on some systems shells can also
1064 * be installed in /usr/bin */
1065 "/bin/bash", "/usr/bin/bash",
1066 "/bin/zsh", "/usr/bin/zsh",
1067 "/bin/tcsh", "/usr/bin/tcsh",
1068 "/bin/ksh", "/usr/bin/ksh",
1069 "/bin/csh", "/bin/sh"
1072 if (geteuid () == getuid () &&
1073 getegid () == getgid ()) {
1074 /* only in non-setuid */
1075 if ((shell = g_getenv ("SHELL"))){
1076 if (access (shell, X_OK) == 0) {
1077 return g_strdup (shell);
1081 pw = getpwuid(getuid());
1082 if (pw && pw->pw_shell) {
1083 if (access (pw->pw_shell, X_OK) == 0) {
1084 return g_strdup (pw->pw_shell);
1088 for (i = 0; i != G_N_ELEMENTS (shells); i++) {
1089 if (access (shells [i], X_OK) == 0) {
1090 return g_strdup (shells[i]);
1094 /* If /bin/sh doesn't exist, your system is truly broken. */
1095 abort ();
1097 /* Placate compiler. */
1098 return NULL;
1099 #else
1100 /* g_find_program_in_path() always looks also in the Windows
1101 * and System32 directories, so it should always find either cmd.exe
1102 * or command.com.
1104 gchar *retval = g_find_program_in_path ("cmd.exe");
1106 if (retval == NULL)
1107 retval = g_find_program_in_path ("command.com");
1109 g_assert (retval != NULL);
1111 return retval;
1112 #endif
1116 * anjuta_util_user_terminal:
1118 * Retrieves the user's preferred terminal.
1120 * Returns: A newly allocated strings list. The first argument is the terminal
1121 * program name. The following are the arguments needed to execute
1122 * a command. The list has to be freed with g_strfreev
1124 /* copied from deprecated gnome_execute_terminal in libgnome */
1125 gchar **
1126 anjuta_util_user_terminal (void)
1128 #ifndef G_OS_WIN32
1129 GConfClient *client;
1130 gchar *terminal = NULL;
1131 gchar **argv = NULL;
1132 static const gchar *terms[] = {
1133 "xdg-terminal",
1134 "gnome-terminal",
1135 "nxterm",
1136 "color-xterm",
1137 "rxvt",
1138 "xterm",
1139 "dtterm",
1140 NULL
1142 const gchar **term;
1144 client = gconf_client_get_default ();
1145 terminal = gconf_client_get_string (client, "/desktop/gnome/applications/terminal/exec", NULL);
1146 g_object_unref (client);
1148 if (terminal)
1150 gchar *command_line;
1151 gchar *exec_flag;
1153 exec_flag = gconf_client_get_string (client, "/desktop/gnome/applications/terminal/exec_arg", NULL);
1154 command_line = g_strconcat (terminal, " ", exec_flag, NULL);
1156 g_shell_parse_argv (command_line, NULL, &argv, NULL);
1157 g_free (terminal);
1158 g_free (exec_flag);
1160 return argv;
1164 /* Search for common ones */
1165 for (term = terms; *term != NULL; term++)
1167 terminal = g_find_program_in_path (*term);
1168 if (terminal != NULL) break;
1171 /* Try xterm */
1172 g_warning (_("Cannot find a terminal; using "
1173 "xterm, even if it may not work"));
1174 terminal = g_strdup ("xterm");
1176 argv = g_new0 (char *, 3);
1177 argv[0] = terminal;
1178 /* Note that gnome-terminal takes -x and
1179 * as -e in gnome-terminal is broken we use that. */
1180 argv[1] = g_strdup (term == &terms[2] ? "-x" : "-e");
1182 return argv;
1183 #else
1184 g_warning ("anjuta_util_user_terminal: Not implemented");
1185 return NULL;
1186 #endif
1189 pid_t
1190 anjuta_util_execute_shell (const gchar *dir, const gchar *command)
1192 pid_t pid;
1193 gchar *shell;
1194 gint err;
1196 g_return_val_if_fail (command != NULL, -1);
1198 shell = anjuta_util_user_shell ();
1199 pid = fork();
1200 if (pid == 0)
1202 if(dir)
1204 anjuta_util_create_dir (dir);
1205 err = chdir (dir);
1207 execlp (shell, shell, "-c", command, NULL);
1208 g_warning (_("Cannot execute command: %s (using shell %s)\n"), command, shell);
1209 _exit(1);
1211 if (pid < 0)
1212 g_warning (_("Cannot execute command: %s (using shell %s)\n"), command, shell);
1213 g_free (shell);
1215 // Anjuta will take care of child exit automatically.
1216 return pid;
1219 pid_t
1220 anjuta_util_execute_terminal_shell (const gchar *dir, const gchar *command)
1222 pid_t pid;
1223 gchar *shell;
1224 gchar **term_argv;
1225 gint err;
1227 g_return_val_if_fail (command != NULL, -1);
1229 shell = anjuta_util_user_shell ();
1230 term_argv = anjuta_util_user_terminal ();
1231 pid = fork();
1232 if (pid == 0)
1234 if(dir)
1236 anjuta_util_create_dir (dir);
1237 err = chdir (dir);
1239 execlp (term_argv[0], term_argv[0], term_argv[1], shell, "-c", command, NULL);
1240 g_warning (_("Cannot execute command: %s (using shell %s)\n"), command, shell);
1241 _exit(1);
1243 if (pid < 0)
1244 g_warning (_("Cannot execute command: %s (using shell %s)\n"), command, shell);
1245 g_free (shell);
1246 g_strfreev (term_argv);
1248 // Anjuta will take care of child exit automatically.
1249 return pid;
1252 gchar *
1253 anjuta_util_convert_to_utf8 (const gchar *str)
1255 GError *error = NULL;
1256 gchar *utf8_msg_string = NULL;
1258 g_return_val_if_fail (str != NULL, NULL);
1259 g_return_val_if_fail (strlen (str) > 0, NULL);
1261 if (g_utf8_validate(str, -1, NULL))
1263 utf8_msg_string = g_strdup (str);
1265 else
1267 gsize rbytes, wbytes;
1268 utf8_msg_string = g_locale_to_utf8 (str, -1, &rbytes, &wbytes, &error);
1269 if (error != NULL) {
1270 g_warning ("g_locale_to_utf8 failed: %s\n", error->message);
1271 g_error_free (error);
1272 /* g_free (utf8_msg_string);
1273 return NULL; */
1276 return utf8_msg_string;
1279 GList*
1280 anjuta_util_parse_args_from_string (const gchar* string)
1282 gboolean escaped;
1283 gchar quote = 0;
1284 gboolean is_quote = FALSE;
1285 gchar* buffer = g_new0(gchar, strlen(string) + 1);
1286 const gchar *s;
1287 gint idx;
1288 GList* args = NULL;
1290 idx = 0;
1291 escaped = FALSE;
1292 s = string;
1294 while (*s) {
1295 if (!isspace(*s))
1296 break;
1297 s++;
1300 while (*s) {
1301 if (escaped) {
1302 /* The current char was escaped */
1303 buffer[idx++] = *s;
1304 escaped = FALSE;
1305 } else if (*s == '\\') {
1306 /* Current char is an escape */
1307 escaped = TRUE;
1308 } else if (is_quote && *s == quote) {
1309 /* Current char ends a quotation */
1310 is_quote = FALSE;
1311 if (!isspace(*(s+1)) && (*(s+1) != '\0')) {
1312 /* If there is no space after the quotation or it is not
1313 the end of the string */
1314 g_warning ("Parse error while parsing program arguments");
1316 } else if ((*s == '\"' || *s == '\'')) {
1317 if (!is_quote) {
1318 /* Current char starts a quotation */
1319 quote = *s;
1320 is_quote = TRUE;
1321 } else {
1322 /* Just a quote char inside quote */
1323 buffer[idx++] = *s;
1325 } else if (is_quote){
1326 /* Any other char inside quote */
1327 buffer[idx++] = *s;
1328 } else if (isspace(*s)) {
1329 /* Any white space outside quote */
1330 if (idx > 0) {
1331 buffer[idx++] = '\0';
1332 args = g_list_append (args, g_strdup (buffer));
1333 idx = 0;
1335 } else {
1336 buffer[idx++] = *s;
1338 s++;
1340 if (idx > 0) {
1341 /* There are chars in the buffer. Flush as the last arg */
1342 buffer[idx++] = '\0';
1343 args = g_list_append (args, g_strdup (buffer));
1344 idx = 0;
1346 if (is_quote) {
1347 g_warning ("Unclosed quotation encountered at the end of parsing");
1349 g_free (buffer);
1350 return args;
1353 gchar*
1354 anjuta_util_escape_quotes(const gchar* str)
1356 gchar *buffer;
1357 gint idx, max_size;
1358 const gchar *s = str;
1360 g_return_val_if_fail(str, NULL);
1361 idx = 0;
1363 /* We are assuming there will be less than 2048 chars to escape */
1364 max_size = strlen(str) + 2048;
1365 buffer = g_new (gchar, max_size);
1366 max_size -= 2;
1368 while(*s) {
1369 if (idx > max_size)
1370 break;
1371 if (*s == '\"' || *s == '\'' || *s == '\\')
1372 buffer[idx++] = '\\';
1373 buffer[idx++] = *s;
1374 s++;
1376 buffer[idx] = '\0';
1377 return buffer;
1380 /* Diff the text contained in uri with text. Return true if files
1381 differ, FALSE if they are identical.*/
1383 gboolean anjuta_util_diff(const gchar* uri, const gchar* text)
1385 GFile *file;
1386 GFileInfo *file_info;
1387 guint64 size;
1388 gchar* file_text = NULL;
1389 gsize bytes_read;
1391 file = g_file_new_for_uri (uri);
1392 file_info = g_file_query_info (file,
1393 G_FILE_ATTRIBUTE_STANDARD_SIZE,
1394 G_FILE_QUERY_INFO_NONE,
1395 NULL,
1396 NULL);
1398 if (file_info == NULL)
1400 g_object_unref (file);
1401 return TRUE;
1404 size = g_file_info_get_attribute_uint64(file_info,
1405 G_FILE_ATTRIBUTE_STANDARD_SIZE);
1406 g_object_unref (file_info);
1408 if (size == 0 && text == NULL)
1410 g_object_unref (file);
1411 return FALSE;
1413 else if (size == 0 || text == NULL)
1415 g_object_unref (file);
1416 return TRUE;
1419 if (!g_file_load_contents(file,
1420 NULL,
1421 &file_text,
1422 &bytes_read,
1423 NULL,
1424 NULL))
1426 g_object_unref (file);
1427 return TRUE;
1429 g_object_unref (file);
1431 if (bytes_read != size)
1433 g_free (file_text);
1434 return TRUE;
1437 /* according to g_file_load_contents's documentation
1438 * file_text is guaranteed to end with \0.
1440 if (strcmp (file_text, text) == 0)
1442 g_free (file_text);
1443 return FALSE;
1446 g_free (file_text);
1447 return TRUE;
1451 * anjuta_util_is_project_file:
1452 * @filename: the file name
1454 * Return TRUE if the file is an anjuta project file. It is implemented by
1455 * checking only the file extension. So it does not check the existence
1456 * of the file. But it is working on an URI if it does not containt a
1457 * fragment.
1459 * Returns: TRUE if the file is a project file, else FALSE
1461 gboolean
1462 anjuta_util_is_project_file (const gchar *filename)
1464 gsize len = strlen (filename);
1465 return ((len > 8) && (strcmp (filename + len - 7, ".anjuta") == 0));
1469 * anjuta_util_is_template_file:
1470 * @filename: the file name
1472 * Return TRUE if the file is an template project file. It is implemented by
1473 * checking only the file extension. So it does not check the existence
1474 * of the file. But it is working on an URI if it does not containt a
1475 * fragment.
1477 * Returns: TRUE if the file is a template file, else FALSE
1479 gboolean
1480 anjuta_util_is_template_file (const gchar *filename)
1482 gsize len = strlen (filename);
1483 return ((len > 9) && (strcmp (filename + len - 8, ".wiz.tgz") == 0));
1487 * anjuta_util_get_file_mine_type:
1488 * @file: the file
1490 * Check if a file exists and return its mime type.
1492 * Returns: NULL if the corresponding file doesn't exist or the mime type as a newly
1493 * allocated string that must be freed with g_free().
1495 gchar *
1496 anjuta_util_get_file_mime_type (GFile *file)
1498 GFileInfo *info;
1499 gchar *mime_type = NULL;
1501 g_return_val_if_fail (file != NULL, NULL);
1503 /* Get file information, check that the file exist at the same time */
1504 info = g_file_query_info (file,
1505 G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
1506 G_FILE_QUERY_INFO_NONE,
1507 NULL,
1508 NULL);
1510 if (info != NULL)
1512 const gchar *extension;
1513 gchar *name;
1515 /* If Anjuta is not installed in system gnome prefix, the mime types
1516 * may not have been correctly registed. In that case, we use the
1517 * following mime detection
1519 name = g_file_get_basename (file);
1520 extension = strrchr(name, '.');
1521 if (extension != NULL)
1523 const static struct {gchar *extension; gchar *type;} anjuta_types[] = {
1524 {"anjuta", "application/x-anjuta"},
1525 {"prj", "application/x-anjuta-old"},
1526 {NULL, NULL}};
1527 gint i;
1529 for (i = 0; anjuta_types[i].extension != NULL; i++)
1531 if (strcmp(extension + 1, anjuta_types[i].extension) == 0)
1533 mime_type = g_strdup (anjuta_types[i].type);
1534 break;
1538 g_free (name);
1540 /* Use mime database if it is not an Anjuta type */
1541 if (mime_type == NULL)
1543 mime_type = g_content_type_get_mime_type (g_file_info_get_content_type(info));
1546 g_object_unref (info);
1549 return mime_type;
1552 gchar *
1553 anjuta_util_get_local_path_from_uri (const gchar *uri)
1555 GFile *file;
1556 gchar *local_path;
1558 file = g_file_new_for_uri (uri);
1559 local_path = g_file_get_path (file);
1560 g_object_unref (file);
1562 return local_path;
1565 #ifdef EMULATE_FORKPTY
1566 #include <grp.h>
1568 static int ptym_open (char *pts_name);
1569 static int ptys_open (int fdm, char * pts_name);
1572 login_tty(int ttyfd)
1574 int fd;
1575 char *fdname;
1577 #ifdef HAVE_SETSID
1578 setsid();
1579 #endif
1580 #ifdef HAVE_SETPGID
1581 setpgid(0, 0);
1582 #endif
1584 /* First disconnect from the old controlling tty. */
1585 #ifdef TIOCNOTTY
1586 fd = open("/dev/tty", O_RDWR|O_NOCTTY);
1587 if (fd >= 0)
1589 ioctl(fd, TIOCNOTTY, NULL);
1590 close(fd);
1592 else
1593 //syslog(LOG_WARNING, "NO CTTY");
1594 #endif /* TIOCNOTTY */
1596 /* Verify that we are successfully disconnected from the controlling tty. */
1597 fd = open("/dev/tty", O_RDWR|O_NOCTTY);
1598 if (fd >= 0)
1600 //syslog(LOG_WARNING, "Failed to disconnect from controlling tty.");
1601 close(fd);
1604 /* Make it our controlling tty. */
1605 #ifdef TIOCSCTTY
1606 ioctl(ttyfd, TIOCSCTTY, NULL);
1607 #endif /* TIOCSCTTY */
1609 fdname = ttyname (ttyfd);
1610 fd = open(fdname, O_RDWR);
1611 if (fd < 0)
1612 ;//syslog(LOG_WARNING, "open %s: %s", fdname, strerror(errno));
1613 else
1614 close(fd);
1616 /* Verify that we now have a controlling tty. */
1617 fd = open("/dev/tty", O_WRONLY);
1618 if (fd < 0)
1620 //syslog(LOG_WARNING, "open /dev/tty: %s", strerror(errno));
1621 return 1;
1624 close(fd);
1625 #if defined(HAVE_VHANGUP) && !defined(HAVE_REVOKE)
1627 RETSIGTYPE (*sig)();
1628 sig = signal(SIGHUP, SIG_IGN);
1629 vhangup();
1630 signal(SIGHUP, sig);
1632 #endif
1633 fd = open(fdname, O_RDWR);
1634 if (fd == -1)
1636 //syslog(LOG_ERR, "can't reopen ctty %s: %s", fdname, strerror(errno));
1637 return -1;
1640 close(ttyfd);
1642 if (fd != 0)
1643 close(0);
1644 if (fd != 1)
1645 close(1);
1646 if (fd != 2)
1647 close(2);
1649 dup2(fd, 0);
1650 dup2(fd, 1);
1651 dup2(fd, 2);
1652 if (fd > 2)
1653 close(fd);
1654 return 0;
1658 openpty(int *amaster, int *aslave, char *name, struct termios *termp,
1659 struct winsize *winp)
1661 char line[20];
1662 *amaster = ptym_open(line);
1663 if (*amaster < 0)
1664 return -1;
1665 *aslave = ptys_open(*amaster, line);
1666 if (*aslave < 0) {
1667 close(*amaster);
1668 return -1;
1670 if (name)
1671 strcpy(name, line);
1672 #ifndef TCSAFLUSH
1673 #define TCSAFLUSH TCSETAF
1674 #endif
1675 if (termp)
1676 (void) tcsetattr(*aslave, TCSAFLUSH, termp);
1677 #ifdef TIOCSWINSZ
1678 if (winp)
1679 (void) ioctl(*aslave, TIOCSWINSZ, (char *)winp);
1680 #endif
1681 return 0;
1684 static int
1685 ptym_open(char * pts_name)
1687 int fdm;
1688 #ifdef HAVE_PTSNAME
1689 char *ptr;
1691 strcpy(pts_name, "/dev/ptmx");
1692 fdm = open(pts_name, O_RDWR);
1693 if (fdm < 0)
1694 return -1;
1695 if (grantpt(fdm) < 0) { /* grant access to slave */
1696 close(fdm);
1697 return -2;
1699 if (unlockpt(fdm) < 0) { /* clear slave's lock flag */
1700 close(fdm);
1701 return -3;
1703 ptr = ptsname(fdm);
1704 if (ptr == NULL) { /* get slave's name */
1705 close (fdm);
1706 return -4;
1708 strcpy(pts_name, ptr); /* return name of slave */
1709 return fdm; /* return fd of master */
1710 #else
1711 char *ptr1, *ptr2;
1713 strcpy(pts_name, "/dev/ptyXY");
1714 /* array index: 012345689 (for references in following code) */
1715 for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1 != 0; ptr1++) {
1716 pts_name[8] = *ptr1;
1717 for (ptr2 = "0123456789abcdef"; *ptr2 != 0; ptr2++) {
1718 pts_name[9] = *ptr2;
1719 /* try to open master */
1720 fdm = open(pts_name, O_RDWR);
1721 if (fdm < 0) {
1722 if (errno == ENOENT) /* different from EIO */
1723 return -1; /* out of pty devices */
1724 else
1725 continue; /* try next pty device */
1727 pts_name[5] = 't'; /* chage "pty" to "tty" */
1728 return fdm; /* got it, return fd of master */
1731 return -1; /* out of pty devices */
1732 #endif
1735 static int
1736 ptys_open(int fdm, char * pts_name)
1738 int fds;
1739 #ifdef HAVE_PTSNAME
1740 /* following should allocate controlling terminal */
1741 fds = open(pts_name, O_RDWR);
1742 if (fds < 0) {
1743 close(fdm);
1744 return -5;
1746 if (ioctl(fds, I_PUSH, "ptem") < 0) {
1747 close(fdm);
1748 close(fds);
1749 return -6;
1751 if (ioctl(fds, I_PUSH, "ldterm") < 0) {
1752 close(fdm);
1753 close(fds);
1754 return -7;
1756 if (ioctl(fds, I_PUSH, "ttcompat") < 0) {
1757 close(fdm);
1758 close(fds);
1759 return -8;
1762 if (ioctl(fdm, I_PUSH, "pckt") < 0) {
1763 close(fdm);
1764 close(fds);
1765 return -8;
1768 if (ioctl(fdm, I_SRDOPT, RMSGN|RPROTDAT) < 0) {
1769 close(fdm);
1770 close(fds);
1771 return -8;
1774 return fds;
1775 #else
1776 int gid;
1777 struct group *grptr;
1779 grptr = getgrnam("tty");
1780 if (grptr != NULL)
1781 gid = grptr->gr_gid;
1782 else
1783 gid = -1; /* group tty is not in the group file */
1784 /* following two functions don't work unless we're root */
1785 chown(pts_name, getuid(), gid);
1786 chmod(pts_name, S_IRUSR | S_IWUSR | S_IWGRP);
1787 fds = open(pts_name, O_RDWR);
1788 if (fds < 0) {
1789 close(fdm);
1790 return -1;
1792 return fds;
1793 #endif
1797 forkpty(int *amaster, char *name, struct termios *termp, struct winsize *winp)
1799 int master, slave, pid;
1801 if (openpty(&master, &slave, name, termp, winp) == -1)
1802 return (-1);
1803 switch (pid = fork()) {
1804 case -1:
1805 return (-1);
1806 case 0:
1808 * child
1810 close(master);
1811 login_tty(slave);
1812 return (0);
1815 * parent
1817 *amaster = master;
1818 close(slave);
1819 return (pid);
1822 int scandir(const char *dir, struct dirent ***namelist,
1823 int (*select)(const struct dirent *),
1824 int (*compar)(const struct dirent **, const struct dirent **))
1826 DIR *d;
1827 struct dirent *entry;
1828 register int i=0;
1829 size_t entrysize;
1831 if ((d=opendir(dir)) == NULL)
1832 return(-1);
1834 *namelist=NULL;
1835 while ((entry=readdir(d)) != NULL)
1837 if (select == NULL || (select != NULL && (*select)(entry)))
1839 *namelist=(struct dirent **)realloc((void *)(*namelist),
1840 (size_t)((i+1)*sizeof(struct dirent *)));
1841 if (*namelist == NULL) return(-1);
1842 entrysize=sizeof(struct dirent)-sizeof(entry->d_name)+strlen(entry->d_name)+1;
1843 (*namelist)[i]=(struct dirent *)malloc(entrysize);
1844 if ((*namelist)[i] == NULL) return(-1);
1845 memcpy((*namelist)[i], entry, entrysize);
1846 i++;
1849 if (closedir(d)) return(-1);
1850 if (i == 0) return(-1);
1851 if (compar != NULL)
1852 qsort((void *)(*namelist), (size_t)i, sizeof(struct dirent *), compar);
1854 return(i);
1857 #endif /* EMULATE_FORKPTY */
1859 void
1860 anjuta_util_help_display (GtkWidget *parent,
1861 const gchar *doc_id,
1862 const gchar *file_name)
1865 GError *error = NULL;
1866 GdkScreen *screen;
1867 gchar *command;
1868 const gchar *lang;
1869 const gchar * const *langs;
1870 gchar *uri = NULL;
1871 gint i;
1873 g_return_if_fail (file_name != NULL);
1875 langs = g_get_language_names ();
1876 for (i = 0; langs[i]; i++)
1878 lang = langs[i];
1879 if (strchr (lang, '.'))
1880 continue;
1882 uri = g_build_filename (DATADIR, "/gnome/help/", doc_id,
1883 lang, file_name, NULL);
1885 if (g_file_test (uri, G_FILE_TEST_EXISTS)) {
1886 break;
1888 g_free (uri);
1889 uri = NULL;
1892 if (uri == NULL)
1894 anjuta_util_dialog_error (GTK_WINDOW (parent), _("Unable to display help. Please make sure the Anjuta "
1895 "documentation package is installed. It can be downloaded "
1896 "from http://anjuta.org."));
1898 return;
1901 command = g_strconcat ("gnome-help ghelp://", uri, NULL);
1902 g_free (uri);
1904 screen = gtk_widget_get_screen (GTK_WIDGET (parent));
1905 gdk_spawn_command_line_on_screen (screen, command, &error);
1906 if (error != NULL)
1908 g_warning ("Error executing help application: %s",
1909 error->message);
1910 g_error_free (error);
1912 return;
1914 g_free (command);
1917 /* The following functions are taken from gedit */
1919 /* Note that this function replace home dir with ~ */
1920 gchar *
1921 anjuta_util_uri_get_dirname (const gchar *uri)
1923 gchar *res;
1924 gchar *str;
1926 // CHECK: does it work with uri chaining? - Paolo
1927 str = g_path_get_dirname (uri);
1928 g_return_val_if_fail (str != NULL, ".");
1930 if ((strlen (str) == 1) && (*str == '.'))
1932 g_free (str);
1934 return NULL;
1937 res = anjuta_util_replace_home_dir_with_tilde (str);
1939 g_free (str);
1941 return res;
1944 gchar*
1945 anjuta_util_replace_home_dir_with_tilde (const gchar *uri)
1947 gchar *tmp;
1948 gchar *home;
1950 g_return_val_if_fail (uri != NULL, NULL);
1952 /* Note that g_get_home_dir returns a const string */
1953 tmp = (gchar *)g_get_home_dir ();
1955 if (tmp == NULL)
1956 return g_strdup (uri);
1958 home = g_filename_to_utf8 (tmp, -1, NULL, NULL, NULL);
1959 if (home == NULL)
1960 return g_strdup (uri);
1962 if (strcmp (uri, home) == 0)
1964 g_free (home);
1966 return g_strdup ("~");
1969 tmp = home;
1970 home = g_strdup_printf ("%s/", tmp);
1971 g_free (tmp);
1973 if (g_str_has_prefix (uri, home))
1975 gchar *res;
1977 res = g_strdup_printf ("~/%s", uri + strlen (home));
1979 g_free (home);
1981 return res;
1984 g_free (home);
1986 return g_strdup (uri);
1990 * anjuta_util_shell_expand:
1991 * @string: input string
1993 * Expand environment variables $(var_name) and tilde (~) in the input string.
1995 * Returns: a newly-allocated string that must be freed with g_free().
1997 gchar*
1998 anjuta_util_shell_expand (const gchar *string)
2000 GString* expand;
2002 if (string == NULL) return NULL;
2004 expand = g_string_sized_new (strlen (string));
2006 for (; *string != '\0'; string++)
2008 switch (*string)
2010 case '$':
2012 /* Variable expansion */
2013 const gchar *end;
2014 gint var_name_len;
2016 end = string + 1;
2017 while (isalnum (*end) || (*end == '_')) end++;
2018 var_name_len = end - string - 1;
2019 if (var_name_len > 0)
2021 const gchar *value;
2023 g_string_append_len (expand, string + 1, var_name_len);
2024 value = g_getenv (expand->str + expand->len - var_name_len);
2025 g_string_truncate (expand, expand->len - var_name_len);
2026 g_string_append (expand, value);
2027 string = end - 1;
2028 continue;
2030 break;
2032 case '~':
2034 /* User home directory expansion */
2035 if (isspace(string[1]) || (string[1] == G_DIR_SEPARATOR) || (string[1] == '\0'))
2037 g_string_append (expand, g_get_home_dir());
2038 continue;
2040 break;
2042 default:
2043 break;
2045 g_string_append_c (expand, *string);
2048 return g_string_free (expand, FALSE);
2051 gchar *
2052 anjuta_util_str_middle_truncate (const gchar *string,
2053 guint truncate_length)
2055 GString *truncated;
2056 guint length;
2057 guint n_chars;
2058 guint num_left_chars;
2059 guint right_offset;
2060 guint delimiter_length;
2061 const gchar *delimiter = "\342\200\246";
2063 g_return_val_if_fail (string != NULL, NULL);
2065 length = strlen (string);
2067 g_return_val_if_fail (g_utf8_validate (string, length, NULL), NULL);
2069 /* It doesnt make sense to truncate strings to less than
2070 * the size of the delimiter plus 2 characters (one on each
2071 * side)
2073 delimiter_length = g_utf8_strlen (delimiter, -1);
2074 if (truncate_length < (delimiter_length + 2)) {
2075 return g_strdup (string);
2078 n_chars = g_utf8_strlen (string, length);
2080 /* Make sure the string is not already small enough. */
2081 if (n_chars <= truncate_length) {
2082 return g_strdup (string);
2085 /* Find the 'middle' where the truncation will occur. */
2086 num_left_chars = (truncate_length - delimiter_length) / 2;
2087 right_offset = n_chars - truncate_length + num_left_chars + delimiter_length;
2089 truncated = g_string_new_len (string,
2090 g_utf8_offset_to_pointer (string, num_left_chars) - string);
2091 g_string_append (truncated, delimiter);
2092 g_string_append (truncated, g_utf8_offset_to_pointer (string, right_offset));
2094 return g_string_free (truncated, FALSE);
2098 * Functions to implement XDG Base Directory Specification
2099 * http://standards.freedesktop.org/basedir-spec/latest/index.html
2100 * Use this to save any config/cache/data files
2104 static gchar*
2105 anjuta_util_construct_pathv (const gchar* str, va_list str_list)
2107 GPtrArray *str_arr;
2108 const gchar* tmp_str;
2109 gchar* path;
2111 str_arr = g_ptr_array_new();
2112 g_ptr_array_add (str_arr, (gpointer) str);
2114 /* Extract elements from va_list */
2115 if (str != NULL)
2117 while ((tmp_str = va_arg (str_list, const gchar*)) != NULL)
2119 g_ptr_array_add (str_arr, (gpointer)tmp_str);
2121 va_end (str_list);
2124 /* Terminate the list */
2125 g_ptr_array_add (str_arr, NULL);
2127 path = g_build_filenamev ((gchar **)str_arr->pdata);
2128 g_ptr_array_free (str_arr, TRUE);
2130 return path;
2133 static GFile*
2134 anjuta_util_get_user_cache_filev (const gchar* path, va_list list)
2136 gchar *uri_str, *base_path, *dir;
2137 GFile *uri;
2138 const gchar anjuta_prefix[] = "anjuta";
2139 base_path = g_build_filename (g_get_user_cache_dir(), anjuta_prefix, path, NULL);
2141 uri_str = anjuta_util_construct_pathv (base_path, list);
2142 g_free (base_path);
2144 uri = g_file_new_for_path (uri_str);
2145 dir = g_path_get_dirname (uri_str);
2146 g_free(uri_str);
2147 if (!anjuta_util_create_dir (dir)) return NULL;
2149 return uri;
2152 GFile*
2153 anjuta_util_get_user_cache_file (const gchar* path, ...)
2155 va_list list;
2156 va_start (list, path);
2157 return anjuta_util_get_user_cache_filev (path, list);
2160 static GFile*
2161 anjuta_util_get_user_config_filev (const gchar* path, va_list list)
2163 gchar *uri_str, *base_path, *dir;
2164 GFile *uri;
2165 const gchar anjuta_prefix[] = "anjuta";
2166 base_path = g_build_filename (g_get_user_config_dir(), anjuta_prefix, path, NULL);
2168 uri_str = anjuta_util_construct_pathv (base_path, list);
2169 g_free (base_path);
2171 uri = g_file_new_for_path (uri_str);
2172 dir = g_path_get_dirname (uri_str);
2173 g_free(uri_str);
2174 if (!anjuta_util_create_dir (dir)) return NULL;
2176 return uri;
2179 GFile*
2180 anjuta_util_get_user_config_file (const gchar* path, ...)
2182 va_list list;
2183 va_start (list, path);
2184 return anjuta_util_get_user_config_filev (path, list);
2187 static GFile*
2188 anjuta_util_get_user_data_filev (const gchar* path, va_list list)
2190 gchar *uri_str, *base_path, *dir;
2191 GFile *uri;
2192 const gchar anjuta_prefix[] = "anjuta";
2193 base_path = g_build_filename (g_get_user_data_dir(), anjuta_prefix, path, NULL);
2195 uri_str = anjuta_util_construct_pathv (base_path, list);
2196 g_free (base_path);
2198 uri = g_file_new_for_path (uri_str);
2199 dir = g_path_get_dirname (uri_str);
2200 g_free(uri_str);
2201 if (!anjuta_util_create_dir (dir)) return NULL;
2203 return uri;
2206 GFile*
2207 anjuta_util_get_user_data_file (const gchar* path, ...)
2209 va_list list;
2210 va_start (list, path);
2211 return anjuta_util_get_user_data_filev (path, list);
2214 gchar*
2215 anjuta_util_get_user_cache_file_path (const gchar* path, ...)
2217 va_list list;
2218 GFile *file;
2219 gchar *file_path;
2220 va_start (list, path);
2221 file = anjuta_util_get_user_cache_filev (path, list);
2222 file_path = g_file_get_path (file);
2223 g_object_unref (file);
2225 return file_path;
2228 gchar*
2229 anjuta_util_get_user_config_file_path (const gchar* path, ...)
2231 va_list list;
2232 GFile *file;
2233 gchar *file_path;
2234 va_start (list, path);
2235 file = anjuta_util_get_user_config_filev (path, list);
2236 file_path = g_file_get_path (file);
2237 g_object_unref (file);
2239 return file_path;
2242 gchar*
2243 anjuta_util_get_user_data_file_path (const gchar* path, ...)
2245 va_list list;
2246 GFile *file;
2247 gchar *file_path;;
2248 va_start (list, path);
2249 file = anjuta_util_get_user_data_filev (path, list);
2250 file_path = g_file_get_path (file);
2251 g_object_unref (file);
2253 return file_path;
2256 GList *
2257 anjuta_util_convert_gfile_list_to_path_list (GList *list)
2259 GList *path_list;
2260 GList *current_file;
2261 gchar *path;
2263 path_list = NULL;
2265 for (current_file = list; current_file != NULL; current_file = g_list_next (current_file))
2267 path = g_file_get_path (current_file->data);
2269 /* Ignore files with invalid paths */
2270 if (path)
2271 path_list = g_list_append (path_list, path);
2274 return path_list;
2277 GList *
2278 anjuta_util_convert_gfile_list_to_relative_path_list (GList *list,
2279 const gchar *parent)
2281 GFile *parent_file;
2282 GList *path_list;
2283 GList *current_file;
2284 gchar *path;
2286 parent_file = g_file_new_for_path (parent);
2287 path_list = NULL;
2289 if (parent_file)
2291 for (current_file = list; current_file != NULL; current_file = g_list_next (current_file))
2293 path = g_file_get_relative_path (parent_file, current_file->data);
2295 /* Ignore files with invalid paths */
2296 if (path)
2297 path_list = g_list_append (path_list, path);
2300 g_object_unref (parent_file);
2303 return path_list;
2308 * anjuta_util_builder_new:
2309 * @filename: Builder file name to open
2310 * @error: Optional error object, if NULL display a dialog if the file is missing
2312 * Create a new GtkBuilder object and load the file in it. Display an error
2313 * if the file is missing. Use a dialog if error is NULL, just a warning
2314 * if the error can be reported.
2316 * Returns: The new GtkBuilder object
2318 GtkBuilder *
2319 anjuta_util_builder_new (const gchar *filename, GError **error)
2321 GtkBuilder *bxml = gtk_builder_new ();
2322 GError *err = NULL;
2324 /* Load glade file */
2325 if (!gtk_builder_add_from_file (bxml, filename, &err))
2327 g_object_unref (bxml);
2328 bxml = NULL;
2330 /* Display the error to the user if it cannot be reported to the caller */
2331 if (error == NULL)
2333 anjuta_util_dialog_error (NULL, _("Unable to load user interface file: %s"), err->message);
2335 else
2337 g_warning ("Couldn't load builder file: %s", err->message);
2339 g_propagate_error (error, err);
2342 /* Tag the builder object with the filename to allow better error message
2343 * with the following function */
2344 if (bxml != NULL)
2346 g_object_set_data_full (G_OBJECT (bxml), "filename", g_strdup (filename), g_free);
2349 return bxml;
2353 * anjuta_util_builder_get_objects:
2354 * @builder: Builder object
2355 * @first_widget: Name of first widget to get
2356 * ...: Address to store the first widget pointer, followed optionally by
2357 * more name/pointer pairs, followed by NULL
2359 * Create a new GtkBuilder object and load the file in it. Display an error
2360 * if the file is missing. Use a dialog if error is NULL, just a warning
2361 * if the error can be reported.
2363 * Returns: TRUE is everything works as expected.
2365 gboolean
2366 anjuta_util_builder_get_objects (GtkBuilder *builder, const gchar *first_widget,...)
2368 va_list args;
2369 const gchar *name;
2370 GObject **object_ptr;
2371 gboolean missing = FALSE;
2373 va_start (args, first_widget);
2375 for (name = first_widget; name; name = va_arg (args, char *))
2377 object_ptr = va_arg (args, void *);
2378 *object_ptr = gtk_builder_get_object (builder, name);
2380 /* Object not found, display a warning */
2381 if (!*object_ptr)
2383 const gchar *filename = (const gchar *)g_object_get_data (G_OBJECT (builder), "filename");
2384 if (filename)
2386 g_warning ("Missing widget '%s' in file %s", name, filename);
2388 else
2390 g_warning("Missing widget '%s'", name);
2392 missing = TRUE;
2395 va_end (args);
2397 return !missing;
2401 * anjuta_utils_drop_get_files:
2402 * @selection_data: the #GtkSelectionData from drag_data_received
2403 * @info: the info from drag_data_received
2405 * Create a list of valid uri's from a uri-list drop.
2407 * Return value: a list of GFiles
2409 GSList*
2410 anjuta_utils_drop_get_files (GtkSelectionData *selection_data)
2412 gchar **uris;
2413 gint i;
2414 GSList* files = NULL;
2416 uris = g_uri_list_extract_uris ((gchar *) gtk_selection_data_get_data (selection_data));
2418 for (i = 0; uris[i] != NULL; i++)
2420 GFile* file = g_file_new_for_uri (uris[i]);
2421 files = g_slist_append(files, file);
2424 return files;