Updated Spanish translation
[anjuta-git-plugin.git] / libanjuta / anjuta-utils.c
blob391722bed44ae1f5eb0eb9f28300ff2b75ef65d1
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 <dirent.h>
44 #include <unistd.h>
45 #include <stdio.h>
46 #include <string.h>
48 #include <glib/gi18n.h>
49 #include <glib.h>
50 #include <glib/gstdio.h>
52 #include <libanjuta/anjuta-utils.h>
53 #include <libanjuta/anjuta-debug.h>
55 #include <libgnomevfs/gnome-vfs.h>
57 #define FILE_BUFFER_SIZE 1024
59 gboolean
60 anjuta_util_copy_file (gchar * src, gchar * dest, gboolean show_error)
62 FILE *input_fp, *output_fp;
63 gchar buffer[FILE_BUFFER_SIZE];
64 gint bytes_read, bytes_written;
65 gboolean error;
67 error = TRUE;
69 input_fp = fopen (src, "rb");
70 if (input_fp == NULL)
72 if( show_error)
73 anjuta_util_dialog_error_system (NULL, errno,
74 _("Unable to read file: %s."),
75 src);
76 return FALSE;
79 output_fp = fopen (dest, "wb");
80 if (output_fp == NULL)
82 if( show_error)
83 anjuta_util_dialog_error_system (NULL, errno,
84 _("Unable to create file: %s."),
85 dest);
86 fclose (input_fp);
87 return TRUE;
90 for (;;)
92 bytes_read = fread (buffer, 1, FILE_BUFFER_SIZE, input_fp);
93 if (bytes_read != FILE_BUFFER_SIZE && ferror (input_fp))
95 error = FALSE;
96 break;
99 if (bytes_read)
101 bytes_written = fwrite (buffer, 1, bytes_read, output_fp);
102 if (bytes_read != bytes_written)
104 error = FALSE;
105 break;
109 if (bytes_read != FILE_BUFFER_SIZE && feof (input_fp))
111 break;
115 fclose (input_fp);
116 fclose (output_fp);
118 if( show_error && (error == FALSE))
119 anjuta_util_dialog_error_system (NULL, errno,
120 _("Unable to complete file copy"));
121 return error;
124 void
125 anjuta_util_color_from_string (const gchar * val, guint16 * r, guint16 * g, guint16 * b)
127 GdkColor color;
128 if (gdk_color_parse(val, &color))
130 *r = color.red;
131 *g = color.green;
132 *b =color.blue;
136 gchar *
137 anjuta_util_string_from_color (guint16 r, guint16 g, guint16 b)
139 return g_strdup_printf("#%02x%02x%02x", r >> 8, g >> 8, b >> 8);
142 /* Get a GdkColor from preferences. Free the color with gdk_color_free() */
143 GdkColor*
144 anjuta_util_convert_color(AnjutaPreferences* prefs, const gchar* pref_name)
146 GdkColor* color = g_new0(GdkColor, 1);
147 gchar* color_string = anjuta_preferences_get(prefs, pref_name);
148 gdk_color_parse(color_string, color);
149 return color;
152 GtkWidget*
153 anjuta_util_button_new_with_stock_image (const gchar* text,
154 const gchar* stock_id)
156 GtkWidget *button;
157 GtkStockItem item;
158 GtkWidget *label;
159 GtkWidget *image;
160 GtkWidget *hbox;
161 GtkWidget *align;
163 button = gtk_button_new ();
165 if (GTK_BIN (button)->child)
166 gtk_container_remove (GTK_CONTAINER (button),
167 GTK_BIN (button)->child);
169 if (gtk_stock_lookup (stock_id, &item))
171 label = gtk_label_new_with_mnemonic (text);
173 gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
175 image = gtk_image_new_from_stock (stock_id, GTK_ICON_SIZE_BUTTON);
176 hbox = gtk_hbox_new (FALSE, 2);
178 align = gtk_alignment_new (0.5, 0.5, 0.0, 0.0);
180 gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, FALSE, 0);
181 gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, FALSE, 0);
183 gtk_container_add (GTK_CONTAINER (button), align);
184 gtk_container_add (GTK_CONTAINER (align), hbox);
185 gtk_widget_show_all (align);
187 return button;
190 label = gtk_label_new_with_mnemonic (text);
191 gtk_label_set_mnemonic_widget (GTK_LABEL (label), GTK_WIDGET (button));
193 gtk_misc_set_alignment (GTK_MISC (label), 0.5, 0.5);
195 gtk_widget_show (label);
196 gtk_container_add (GTK_CONTAINER (button), label);
198 return button;
201 GtkWidget*
202 anjuta_util_dialog_add_button (GtkDialog *dialog, const gchar* text,
203 const gchar* stock_id, gint response_id)
205 GtkWidget *button;
207 g_return_val_if_fail (GTK_IS_DIALOG (dialog), NULL);
208 g_return_val_if_fail (text != NULL, NULL);
209 g_return_val_if_fail (stock_id != NULL, NULL);
211 button = anjuta_util_button_new_with_stock_image (text, stock_id);
212 g_return_val_if_fail (button != NULL, NULL);
214 GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT);
216 gtk_widget_show (button);
218 gtk_dialog_add_action_widget (dialog, button, response_id);
220 return button;
223 void
224 anjuta_util_dialog_error (GtkWindow *parent, const gchar *mesg, ...)
226 gchar* message;
227 va_list args;
228 GtkWidget *dialog;
229 GtkWindow *real_parent;
231 va_start (args, mesg);
232 message = g_strdup_vprintf (mesg, args);
233 va_end (args);
235 if (parent && GTK_IS_WINDOW (parent))
237 real_parent = parent;
239 else
241 real_parent = NULL;
244 // Dialog to be HIG compliant
245 dialog = gtk_message_dialog_new (real_parent,
246 GTK_DIALOG_DESTROY_WITH_PARENT,
247 GTK_MESSAGE_ERROR,
248 GTK_BUTTONS_CLOSE, message);
249 g_signal_connect (G_OBJECT (dialog), "response",
250 G_CALLBACK (gtk_widget_destroy), NULL);
251 gtk_widget_show (dialog);
252 g_free (message);
255 void
256 anjuta_util_dialog_warning (GtkWindow *parent, const gchar * mesg, ...)
258 gchar* message;
259 va_list args;
260 GtkWidget *dialog;
261 GtkWindow *real_parent;
263 va_start (args, mesg);
264 message = g_strdup_vprintf (mesg, args);
265 va_end (args);
267 if (parent && GTK_IS_WINDOW (parent))
269 real_parent = parent;
271 else
273 real_parent = NULL;
276 // Dialog to be HIG compliant
277 dialog = gtk_message_dialog_new (real_parent,
278 GTK_DIALOG_DESTROY_WITH_PARENT,
279 GTK_MESSAGE_WARNING,
280 GTK_BUTTONS_CLOSE, message);
281 g_signal_connect (G_OBJECT (dialog), "response",
282 G_CALLBACK (gtk_widget_destroy), NULL);
283 gtk_widget_show (dialog);
284 g_free (message);
287 void
288 anjuta_util_dialog_info (GtkWindow *parent, const gchar * mesg, ...)
290 gchar* message;
291 va_list args;
292 GtkWidget *dialog;
293 GtkWindow *real_parent;
295 va_start (args, mesg);
296 message = g_strdup_vprintf (mesg, args);
297 va_end (args);
299 if (parent && GTK_IS_WINDOW (parent))
301 real_parent = parent;
303 else
305 real_parent = NULL;
307 // Dialog to be HIG compliant
308 dialog = gtk_message_dialog_new (real_parent,
309 GTK_DIALOG_DESTROY_WITH_PARENT,
310 GTK_MESSAGE_INFO,
311 GTK_BUTTONS_CLOSE, message);
312 g_signal_connect (G_OBJECT (dialog), "response",
313 G_CALLBACK (gtk_widget_destroy), NULL);
314 gtk_widget_show (dialog);
315 g_free (message);
318 void
319 anjuta_util_dialog_error_system (GtkWindow* parent, gint errnum,
320 const gchar * mesg, ... )
322 gchar* message;
323 gchar* tot_mesg;
324 va_list args;
325 GtkWidget *dialog;
326 GtkWindow *real_parent;
328 va_start (args, mesg);
329 message = g_strdup_vprintf (mesg, args);
330 va_end (args);
332 if (0 != errnum) {
333 tot_mesg = g_strconcat (message, _("\nSystem: "),
334 g_strerror(errnum), NULL);
335 g_free (message);
336 } else
337 tot_mesg = message;
339 if (parent && GTK_IS_WINDOW (parent))
341 real_parent = parent;
343 else
345 real_parent = NULL;
347 // Dialog to be HIG compliant
348 dialog = gtk_message_dialog_new (real_parent,
349 GTK_DIALOG_DESTROY_WITH_PARENT,
350 GTK_MESSAGE_ERROR,
351 GTK_BUTTONS_CLOSE, tot_mesg);
352 g_signal_connect (G_OBJECT (dialog), "response",
353 G_CALLBACK (gtk_widget_destroy), NULL);
354 gtk_widget_show (dialog);
355 g_free (tot_mesg);
358 gboolean
359 anjuta_util_dialog_boolean_question (GtkWindow *parent, const gchar *mesg, ...)
361 gchar* message;
362 va_list args;
363 GtkWidget *dialog;
364 gint ret;
365 GtkWindow *real_parent;
367 va_start (args, mesg);
368 message = g_strdup_vprintf (mesg, args);
369 va_end (args);
371 if (parent && GTK_IS_WINDOW (parent))
373 real_parent = parent;
375 else
377 real_parent = NULL;
380 dialog = gtk_message_dialog_new (real_parent,
381 GTK_DIALOG_DESTROY_WITH_PARENT,
382 GTK_MESSAGE_QUESTION,
383 GTK_BUTTONS_YES_NO, message);
385 ret = gtk_dialog_run (GTK_DIALOG (dialog));
386 gtk_widget_destroy (dialog);
387 g_free (message);
389 return (ret == GTK_RESPONSE_YES);
392 gboolean
393 anjuta_util_dialog_input (GtkWindow *parent, const gchar *prompt,
394 const gchar *default_value, gchar **return_value)
396 GtkWidget *dialog, *label, *frame, *entry, *dialog_vbox, *vbox;
397 gint res;
398 gchar *markup;
399 GtkWindow *real_parent;
401 if (parent && GTK_IS_WINDOW (parent))
403 real_parent = parent;
405 else
407 real_parent = NULL;
410 dialog = gtk_dialog_new_with_buttons (prompt, real_parent,
411 GTK_DIALOG_DESTROY_WITH_PARENT,
412 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
413 GTK_STOCK_OK, GTK_RESPONSE_OK,
414 NULL);
415 gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
416 dialog_vbox = GTK_DIALOG (dialog)->vbox;
417 gtk_window_set_default_size (GTK_WINDOW (dialog), 400, -1);
418 gtk_widget_show (dialog_vbox);
420 markup = g_strconcat ("<b>", prompt, "</b>", NULL);
421 label = gtk_label_new (NULL);
422 gtk_label_set_markup (GTK_LABEL (label), markup);
423 gtk_widget_show (label);
424 g_free (markup);
426 frame = gtk_frame_new (NULL);
427 gtk_frame_set_label_widget (GTK_FRAME (frame), label);
428 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_NONE);
429 gtk_container_set_border_width (GTK_CONTAINER (frame), 10);
430 gtk_widget_show (frame);
431 gtk_box_pack_start (GTK_BOX (dialog_vbox), frame, FALSE, FALSE, 0);
433 vbox = gtk_vbox_new (FALSE, 0);
434 gtk_widget_show (vbox);
435 gtk_container_set_border_width (GTK_CONTAINER (vbox), 10);
436 gtk_container_add (GTK_CONTAINER (frame), vbox);
438 entry = gtk_entry_new ();
439 gtk_widget_show (entry);
440 gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
441 gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0);
442 if (default_value)
443 gtk_entry_set_text (GTK_ENTRY (entry), default_value);
445 res = gtk_dialog_run (GTK_DIALOG (dialog));
447 if (gtk_entry_get_text (GTK_ENTRY (entry)) &&
448 strlen (gtk_entry_get_text (GTK_ENTRY (entry))) > 0)
450 *return_value = g_strdup (gtk_entry_get_text (GTK_ENTRY (entry)));
452 else
454 *return_value = NULL;
456 gtk_widget_destroy (dialog);
457 return (res == GTK_RESPONSE_OK);
460 gboolean
461 anjuta_util_prog_is_installed (gchar * prog, gboolean show)
463 gchar* prog_path = g_find_program_in_path (prog);
464 if (prog_path)
466 g_free (prog_path);
467 return TRUE;
469 if (show)
471 anjuta_util_dialog_error (NULL, _("The \"%s\" utility is not installed.\n"
472 "Please install it."), prog);
474 return FALSE;
477 gchar *
478 anjuta_util_get_a_tmp_file (void)
480 static gint count = 0;
481 gchar *filename;
482 const gchar *tmpdir;
484 tmpdir = g_get_tmp_dir ();
485 filename =
486 g_strdup_printf ("%s/anjuta_%d.%d", tmpdir, count++, getpid ());
487 return filename;
490 /* GList of strings operations */
491 GList *
492 anjuta_util_glist_from_string (const gchar *string)
494 gchar *str, *temp, buff[256];
495 GList *list;
496 gchar *word_start, *word_end;
497 gboolean the_end;
499 list = NULL;
500 the_end = FALSE;
501 temp = g_strdup (string);
502 str = temp;
503 if (!str)
504 return NULL;
506 while (1)
508 gint i;
509 gchar *ptr;
511 /* Remove leading spaces */
512 while (isspace (*str) && *str != '\0')
513 str++;
514 if (*str == '\0')
515 break;
517 /* Find start and end of word */
518 word_start = str;
519 while (!isspace (*str) && *str != '\0')
520 str++;
521 word_end = str;
523 /* Copy the word into the buffer */
524 for (ptr = word_start, i = 0; ptr < word_end; ptr++, i++)
525 buff[i] = *ptr;
526 buff[i] = '\0';
527 if (strlen (buff))
528 list = g_list_append (list, g_strdup (buff));
529 if (*str == '\0')
530 break;
532 if (temp)
533 g_free (temp);
534 return list;
537 /* Prefix the strings */
538 void
539 anjuta_util_glist_strings_prefix (GList * list, const gchar *prefix)
541 GList *node;
542 node = list;
544 g_return_if_fail (prefix != NULL);
545 while (node)
547 gchar* tmp;
548 tmp = node->data;
549 node->data = g_strconcat (prefix, tmp, NULL);
550 if (tmp) g_free (tmp);
551 node = g_list_next (node);
555 /* Suffix the strings */
556 void
557 anjuta_util_glist_strings_sufix (GList * list, const gchar *sufix)
559 GList *node;
560 node = list;
562 g_return_if_fail (sufix != NULL);
563 while (node)
565 gchar* tmp;
566 tmp = node->data;
567 node->data = g_strconcat (tmp, sufix, NULL);
568 if (tmp) g_free (tmp);
569 node = g_list_next (node);
573 /* Duplicate list of strings */
574 GList*
575 anjuta_util_glist_strings_dup (GList * list)
577 GList *node;
578 GList *new_list;
580 new_list = NULL;
581 node = list;
582 while (node)
584 if (node->data)
585 new_list = g_list_append (new_list, g_strdup(node->data));
586 else
587 new_list = g_list_append (new_list, NULL);
588 node = g_list_next (node);
590 return new_list;
593 /* Join list of strings using the given delimiter */
594 gchar*
595 anjuta_util_glist_strings_join (GList * list, gchar *delimiter)
597 GString *joined;
598 gboolean first = TRUE;
599 GList *node;
601 joined = g_string_new (NULL);
602 node = list;
603 while (node)
605 if (node->data)
607 if (!first)
608 g_string_append (joined, delimiter);
609 else
610 first = FALSE;
611 g_string_append (joined, node->data);
613 node = g_list_next (node);
615 if (joined->len > 0)
616 return g_string_free (joined, FALSE);
617 else
618 g_string_free (joined, TRUE);
619 return NULL;
622 gchar*
623 anjuta_util_get_real_path (const gchar *path)
625 if (path != NULL)
627 gchar *result;
628 #ifdef PATH_MAX
629 gchar buf[PATH_MAX+1];
631 result = realpath (path, buf);
632 if (result != NULL)
634 *(buf + PATH_MAX) = '\0'; /* ensure a terminator */
635 return g_strdup (buf);
637 #else
638 char *buf;
639 /* the string returned by realpath should be cleaned with
640 free(), not g_free() */
641 buf = realpath (path, NULL);
642 if (buf != NULL)
644 result = g_strdup (buf);
645 free (buf);
646 return result;
648 #endif
650 return NULL;
653 /* Dedup a list of paths - duplicates are removed from the tail.
654 ** Useful for deduping Recent Files and Recent Projects */
655 GList*
656 anjuta_util_glist_path_dedup(GList *list)
658 GList *nlist = NULL, *tmp, *tmp1;
659 gchar *path;
660 struct stat s;
661 for (tmp = list; tmp; tmp = g_list_next(tmp))
663 path = anjuta_util_get_real_path ((const gchar *) tmp->data);
664 if (path)
666 if (stat (path, &s) != 0)
668 g_free(path);
670 else
672 for (tmp1 = nlist; tmp1; tmp1 = g_list_next(tmp1))
674 if (0 == strcmp((const char *) tmp1->data, path))
676 g_free(path);
677 path = NULL;
678 break;
681 if (path)
682 nlist = g_list_prepend(nlist, path);
686 anjuta_util_glist_strings_free(list);
687 nlist = g_list_reverse(nlist);
688 return nlist;
691 static gint
692 sort_node (gchar* a, gchar *b)
694 if ( !a && !b) return 0;
695 else if (!a) return -1;
696 else if (!b) return 1;
697 return strcmp (a, b);
700 /* Sort the list alphabatically */
701 GList*
702 anjuta_util_glist_strings_sort (GList * list)
704 return g_list_sort(list, (GCompareFunc)sort_node);
707 /* Free the strings and GList */
708 void
709 anjuta_util_glist_strings_free (GList * list)
711 GList *node;
712 node = list;
713 while (node)
715 if (node->data)
716 g_free (node->data);
717 node = g_list_next (node);
719 g_list_free (list);
723 anjuta_util_type_from_string (AnjutaUtilStringMap *map, const char *str)
725 int i = 0;
727 while (-1 != map[i].type)
729 if (0 == strcmp(map[i].name, str))
730 return map[i].type;
731 ++ i;
733 return -1;
736 const char*
737 anjuta_util_string_from_type (AnjutaUtilStringMap *map, int type)
739 int i = 0;
740 while (-1 != map[i].type)
742 if (map[i].type == type)
743 return map[i].name;
744 ++ i;
746 return "";
749 GList*
750 anjuta_util_glist_from_map (AnjutaUtilStringMap *map)
752 GList *out_list = NULL;
753 int i = 0;
754 while (-1 != map[i].type)
756 out_list = g_list_append(out_list, map[i].name);
757 ++ i;
759 return out_list;
763 GList *
764 anjuta_util_update_string_list (GList *p_list, const gchar *p_str, gint length)
766 gint i;
767 gchar *str;
768 if (!p_str)
769 return p_list;
770 for (i = 0; i < g_list_length (p_list); i++)
772 str = (gchar *) g_list_nth_data (p_list, i);
773 if (!str)
774 continue;
775 if (strcmp (p_str, str) == 0)
777 p_list = g_list_remove (p_list, str);
778 p_list = g_list_prepend (p_list, str);
779 return p_list;
782 p_list = g_list_prepend (p_list, g_strdup (p_str));
783 while (g_list_length (p_list) > length)
785 str = g_list_nth_data (p_list, g_list_length (p_list) - 1);
786 p_list = g_list_remove (p_list, str);
787 g_free (str);
789 return p_list;
792 gboolean
793 anjuta_util_create_dir (const gchar * d)
795 if (g_file_test (d, G_FILE_TEST_IS_DIR))
796 return TRUE;
797 if (mkdir (d, 0755))
798 return FALSE;
799 return TRUE;
802 pid_t
803 anjuta_util_execute_shell (const gchar *dir, const gchar *command)
805 pid_t pid;
806 gchar *shell;
808 g_return_val_if_fail (command != NULL, -1);
810 shell = gnome_util_user_shell ();
811 pid = fork();
812 if (pid == 0)
814 if(dir)
816 anjuta_util_create_dir (dir);
817 chdir (dir);
819 execlp (shell, shell, "-c", command, NULL);
820 g_warning (_("Cannot execute command: %s (using shell %s)\n"), command, shell);
821 _exit(1);
823 if (pid < 0)
824 g_warning (_("Cannot execute command: %s (using shell %s)\n"), command, shell);
825 g_free (shell);
826 // Anjuta will take care of child exit automatically.
827 return pid;
830 gchar *
831 anjuta_util_convert_to_utf8 (const gchar *str)
833 GError *error = NULL;
834 gchar *utf8_msg_string = NULL;
836 g_return_val_if_fail (str != NULL, NULL);
837 g_return_val_if_fail (strlen (str) > 0, NULL);
839 if (g_utf8_validate(str, -1, NULL))
841 utf8_msg_string = g_strdup (str);
843 else
845 gsize rbytes, wbytes;
846 utf8_msg_string = g_locale_to_utf8 (str, -1, &rbytes, &wbytes, &error);
847 if (error != NULL) {
848 g_warning ("g_locale_to_utf8 failed: %s\n", error->message);
849 g_error_free (error);
850 /* g_free (utf8_msg_string);
851 return NULL; */
854 return utf8_msg_string;
857 GList*
858 anjuta_util_parse_args_from_string (const gchar* string)
860 gboolean escaped;
861 gchar quote = 0;
862 gboolean is_quote = FALSE;
863 gchar* buffer = g_new0(gchar, strlen(string) + 1);
864 const gchar *s;
865 gint idx;
866 GList* args = NULL;
868 idx = 0;
869 escaped = FALSE;
870 s = string;
872 while (*s) {
873 if (!isspace(*s))
874 break;
875 s++;
878 while (*s) {
879 if (escaped) {
880 /* The current char was escaped */
881 buffer[idx++] = *s;
882 escaped = FALSE;
883 } else if (*s == '\\') {
884 /* Current char is an escape */
885 escaped = TRUE;
886 } else if (is_quote && *s == quote) {
887 /* Current char ends a quotation */
888 is_quote = FALSE;
889 if (!isspace(*(s+1)) && (*(s+1) != '\0')) {
890 /* If there is no space after the quotation or it is not
891 the end of the string */
892 g_warning ("Parse error while parsing program arguments");
894 } else if ((*s == '\"' || *s == '\'')) {
895 if (!is_quote) {
896 /* Current char starts a quotation */
897 quote = *s;
898 is_quote = TRUE;
899 } else {
900 /* Just a quote char inside quote */
901 buffer[idx++] = *s;
903 } else if (is_quote){
904 /* Any other char inside quote */
905 buffer[idx++] = *s;
906 } else if (isspace(*s)) {
907 /* Any white space outside quote */
908 if (idx > 0) {
909 buffer[idx++] = '\0';
910 args = g_list_append (args, g_strdup (buffer));
911 idx = 0;
913 } else {
914 buffer[idx++] = *s;
916 s++;
918 if (idx > 0) {
919 /* There are chars in the buffer. Flush as the last arg */
920 buffer[idx++] = '\0';
921 args = g_list_append (args, g_strdup (buffer));
922 idx = 0;
924 if (is_quote) {
925 g_warning ("Unclosed quotation encountered at the end of parsing");
927 return args;
930 gchar*
931 anjuta_util_escape_quotes(const gchar* str)
933 gchar *buffer;
934 gint idx, max_size;
935 const gchar *s = str;
937 g_return_val_if_fail(str, NULL);
938 idx = 0;
940 /* We are assuming there will be less than 2048 chars to escape */
941 max_size = strlen(str) + 2048;
942 buffer = g_new (gchar, max_size);
943 max_size -= 2;
945 while(*s) {
946 if (idx > max_size)
947 break;
948 if (*s == '\"' || *s == '\'' || *s == '\\')
949 buffer[idx++] = '\\';
950 buffer[idx++] = *s;
951 s++;
953 buffer[idx] = '\0';
954 return buffer;
957 /* Diff the text contained in uri with text. Return true if files
958 differ, FALSE if they are identical.
959 FIXME: Find a better algorithm, this seems ineffective */
961 gboolean anjuta_util_diff(const gchar* uri, const gchar* text)
963 GnomeVFSFileSize bytes_read;
964 gchar* file_text;
965 GnomeVFSFileInfo info;
966 GnomeVFSHandle* handle = NULL;
968 gnome_vfs_get_file_info(uri, &info, GNOME_VFS_FILE_INFO_DEFAULT);
970 if (info.size == 0 && text == NULL)
971 return FALSE;
972 else if (info.size == 0 || text == NULL)
973 return TRUE;
975 file_text = g_new0(gchar, info.size + 1);
977 if (gnome_vfs_open(&handle, uri, GNOME_VFS_OPEN_READ != GNOME_VFS_OK))
978 return TRUE;
980 if ((gnome_vfs_read(handle, file_text, info.size, &bytes_read) == GNOME_VFS_OK)
981 && (bytes_read == info.size))
983 gnome_vfs_close(handle);
985 if ((g_utf8_strlen(file_text, -1) == g_utf8_strlen(text, -1))
986 && strcmp(file_text, text) == 0)
987 return FALSE;
988 return TRUE;
990 else
992 gnome_vfs_close(handle);
993 return TRUE;
997 gboolean
998 anjuta_util_path_has_extension (const gchar *path, const gchar *ext)
1000 if (strlen (path) <= strlen (ext))
1001 return FALSE;
1002 if ((path[strlen (path) - strlen (ext) - 1] == '.') &&
1003 (strcmp (&path[strlen (path) - strlen (ext)], ext) == 0))
1004 return TRUE;
1005 return FALSE;
1008 gchar *
1009 anjuta_util_get_uri_mime_type (const gchar *uri)
1011 GnomeVFSURI *vfs_uri;
1012 const gchar *path;
1013 gchar *mime_type;
1015 g_return_val_if_fail (uri != NULL, NULL);
1017 vfs_uri = gnome_vfs_uri_new (uri);
1018 if (vfs_uri)
1019 path = gnome_vfs_uri_get_path (vfs_uri);
1020 else
1021 path = NULL;
1023 /* If Anjuta is not installed in system gnome prefix, the mime types
1024 * may not have been correctly registed. In that case, we use the
1025 * following mime detection
1027 if (!path)
1029 mime_type = gnome_vfs_get_slow_mime_type (uri);
1031 else if (anjuta_util_path_has_extension (path, "anjuta"))
1033 mime_type = g_strdup ("application/x-anjuta");
1035 else if (anjuta_util_path_has_extension (path, "prj"))
1037 mime_type = g_strdup ("application/x-anjuta-old");
1039 else if (anjuta_util_path_has_extension (path, "ui"))
1041 mime_type = g_strdup ("text/xml");
1043 else if (anjuta_util_path_has_extension (path, "glade"))
1045 mime_type = g_strdup ("application/x-glade");
1047 else
1049 mime_type = gnome_vfs_get_slow_mime_type (uri);
1052 if (vfs_uri)
1053 gnome_vfs_uri_unref (vfs_uri);
1054 return mime_type;
1057 #ifndef HAVE_LIBUTIL
1058 #include <grp.h>
1060 static int ptym_open (char *pts_name);
1061 static int ptys_open (int fdm, char * pts_name);
1064 login_tty(int ttyfd)
1066 int fd;
1067 char *fdname;
1069 #ifdef HAVE_SETSID
1070 setsid();
1071 #endif
1072 #ifdef HAVE_SETPGID
1073 setpgid(0, 0);
1074 #endif
1076 /* First disconnect from the old controlling tty. */
1077 #ifdef TIOCNOTTY
1078 fd = open("/dev/tty", O_RDWR|O_NOCTTY);
1079 if (fd >= 0)
1081 ioctl(fd, TIOCNOTTY, NULL);
1082 close(fd);
1084 else
1085 //syslog(LOG_WARNING, "NO CTTY");
1086 #endif /* TIOCNOTTY */
1088 /* Verify that we are successfully disconnected from the controlling tty. */
1089 fd = open("/dev/tty", O_RDWR|O_NOCTTY);
1090 if (fd >= 0)
1092 //syslog(LOG_WARNING, "Failed to disconnect from controlling tty.");
1093 close(fd);
1096 /* Make it our controlling tty. */
1097 #ifdef TIOCSCTTY
1098 ioctl(ttyfd, TIOCSCTTY, NULL);
1099 #endif /* TIOCSCTTY */
1101 fdname = ttyname (ttyfd);
1102 fd = open(fdname, O_RDWR);
1103 if (fd < 0)
1104 ;//syslog(LOG_WARNING, "open %s: %s", fdname, strerror(errno));
1105 else
1106 close(fd);
1108 /* Verify that we now have a controlling tty. */
1109 fd = open("/dev/tty", O_WRONLY);
1110 if (fd < 0)
1112 //syslog(LOG_WARNING, "open /dev/tty: %s", strerror(errno));
1113 return 1;
1116 close(fd);
1117 #if defined(HAVE_VHANGUP) && !defined(HAVE_REVOKE)
1119 RETSIGTYPE (*sig)();
1120 sig = signal(SIGHUP, SIG_IGN);
1121 vhangup();
1122 signal(SIGHUP, sig);
1124 #endif
1125 fd = open(fdname, O_RDWR);
1126 if (fd == -1)
1128 //syslog(LOG_ERR, "can't reopen ctty %s: %s", fdname, strerror(errno));
1129 return -1;
1132 close(ttyfd);
1134 if (fd != 0)
1135 close(0);
1136 if (fd != 1)
1137 close(1);
1138 if (fd != 2)
1139 close(2);
1141 dup2(fd, 0);
1142 dup2(fd, 1);
1143 dup2(fd, 2);
1144 if (fd > 2)
1145 close(fd);
1146 return 0;
1150 openpty(int *amaster, int *aslave, char *name, struct termios *termp,
1151 struct winsize *winp)
1153 char line[20];
1154 *amaster = ptym_open(line);
1155 if (*amaster < 0)
1156 return -1;
1157 *aslave = ptys_open(*amaster, line);
1158 if (*aslave < 0) {
1159 close(*amaster);
1160 return -1;
1162 if (name)
1163 strcpy(name, line);
1164 #ifndef TCSAFLUSH
1165 #define TCSAFLUSH TCSETAF
1166 #endif
1167 if (termp)
1168 (void) tcsetattr(*aslave, TCSAFLUSH, termp);
1169 #ifdef TIOCSWINSZ
1170 if (winp)
1171 (void) ioctl(*aslave, TIOCSWINSZ, (char *)winp);
1172 #endif
1173 return 0;
1176 static int
1177 ptym_open(char * pts_name)
1179 int fdm;
1180 #ifdef HAVE_PTSNAME
1181 char *ptr;
1183 strcpy(pts_name, "/dev/ptmx");
1184 fdm = open(pts_name, O_RDWR);
1185 if (fdm < 0)
1186 return -1;
1187 if (grantpt(fdm) < 0) { /* grant access to slave */
1188 close(fdm);
1189 return -2;
1191 if (unlockpt(fdm) < 0) { /* clear slave's lock flag */
1192 close(fdm);
1193 return -3;
1195 ptr = ptsname(fdm);
1196 if (ptr == NULL) { /* get slave's name */
1197 close (fdm);
1198 return -4;
1200 strcpy(pts_name, ptr); /* return name of slave */
1201 return fdm; /* return fd of master */
1202 #else
1203 char *ptr1, *ptr2;
1205 strcpy(pts_name, "/dev/ptyXY");
1206 /* array index: 012345689 (for references in following code) */
1207 for (ptr1 = "pqrstuvwxyzPQRST"; *ptr1 != 0; ptr1++) {
1208 pts_name[8] = *ptr1;
1209 for (ptr2 = "0123456789abcdef"; *ptr2 != 0; ptr2++) {
1210 pts_name[9] = *ptr2;
1211 /* try to open master */
1212 fdm = open(pts_name, O_RDWR);
1213 if (fdm < 0) {
1214 if (errno == ENOENT) /* different from EIO */
1215 return -1; /* out of pty devices */
1216 else
1217 continue; /* try next pty device */
1219 pts_name[5] = 't'; /* chage "pty" to "tty" */
1220 return fdm; /* got it, return fd of master */
1223 return -1; /* out of pty devices */
1224 #endif
1227 static int
1228 ptys_open(int fdm, char * pts_name)
1230 int fds;
1231 #ifdef HAVE_PTSNAME
1232 /* following should allocate controlling terminal */
1233 fds = open(pts_name, O_RDWR);
1234 if (fds < 0) {
1235 close(fdm);
1236 return -5;
1238 if (ioctl(fds, I_PUSH, "ptem") < 0) {
1239 close(fdm);
1240 close(fds);
1241 return -6;
1243 if (ioctl(fds, I_PUSH, "ldterm") < 0) {
1244 close(fdm);
1245 close(fds);
1246 return -7;
1248 if (ioctl(fds, I_PUSH, "ttcompat") < 0) {
1249 close(fdm);
1250 close(fds);
1251 return -8;
1254 if (ioctl(fdm, I_PUSH, "pckt") < 0) {
1255 close(fdm);
1256 close(fds);
1257 return -8;
1260 if (ioctl(fdm, I_SRDOPT, RMSGN|RPROTDAT) < 0) {
1261 close(fdm);
1262 close(fds);
1263 return -8;
1266 return fds;
1267 #else
1268 int gid;
1269 struct group *grptr;
1271 grptr = getgrnam("tty");
1272 if (grptr != NULL)
1273 gid = grptr->gr_gid;
1274 else
1275 gid = -1; /* group tty is not in the group file */
1276 /* following two functions don't work unless we're root */
1277 chown(pts_name, getuid(), gid);
1278 chmod(pts_name, S_IRUSR | S_IWUSR | S_IWGRP);
1279 fds = open(pts_name, O_RDWR);
1280 if (fds < 0) {
1281 close(fdm);
1282 return -1;
1284 return fds;
1285 #endif
1289 forkpty(int *amaster, char *name, struct termios *termp, struct winsize *winp)
1291 int master, slave, pid;
1293 if (openpty(&master, &slave, name, termp, winp) == -1)
1294 return (-1);
1295 switch (pid = fork()) {
1296 case -1:
1297 return (-1);
1298 case 0:
1300 * child
1302 close(master);
1303 login_tty(slave);
1304 return (0);
1307 * parent
1309 *amaster = master;
1310 close(slave);
1311 return (pid);
1314 int scandir(const char *dir, struct dirent ***namelist,
1315 int (*select)(const struct dirent *),
1316 int (*compar)(const struct dirent **, const struct dirent **))
1318 DIR *d;
1319 struct dirent *entry;
1320 register int i=0;
1321 size_t entrysize;
1323 if ((d=opendir(dir)) == NULL)
1324 return(-1);
1326 *namelist=NULL;
1327 while ((entry=readdir(d)) != NULL)
1329 if (select == NULL || (select != NULL && (*select)(entry)))
1331 *namelist=(struct dirent **)realloc((void *)(*namelist),
1332 (size_t)((i+1)*sizeof(struct dirent *)));
1333 if (*namelist == NULL) return(-1);
1334 entrysize=sizeof(struct dirent)-sizeof(entry->d_name)+strlen(entry->d_name)+1;
1335 (*namelist)[i]=(struct dirent *)malloc(entrysize);
1336 if ((*namelist)[i] == NULL) return(-1);
1337 memcpy((*namelist)[i], entry, entrysize);
1338 i++;
1341 if (closedir(d)) return(-1);
1342 if (i == 0) return(-1);
1343 if (compar != NULL)
1344 qsort((void *)(*namelist), (size_t)i, sizeof(struct dirent *), compar);
1346 return(i);
1349 #endif /* HAVE_LIBUTIL */
1351 void
1352 anjuta_util_help_display (GtkWindow *parent,
1353 const gchar *doc_id,
1354 const gchar *file_name)
1357 GError *error = NULL;
1358 GdkScreen *screen;
1359 gchar *command;
1360 const gchar *lang;
1361 const gchar * const *langs;
1362 gchar *uri = NULL;
1363 gint i;
1365 g_return_if_fail (file_name != NULL);
1367 langs = g_get_language_names ();
1368 for (i = 0; langs[i]; i++)
1370 lang = langs[i];
1371 if (strchr (lang, '.'))
1372 continue;
1374 uri = g_build_filename (DATADIR, "/gnome/help/", doc_id,
1375 lang, file_name, NULL);
1377 if (g_file_test (uri, G_FILE_TEST_EXISTS)) {
1378 break;
1380 g_free (uri);
1381 uri = NULL;
1384 if (uri == NULL)
1386 anjuta_util_dialog_error (parent, _("Unable to display help. Please make sure Anjuta "
1387 "documentation package is install. It can be downloaded "
1388 "from http://anjuta.org"));
1390 return;
1393 command = g_strconcat ("gnome-help ghelp://", uri, NULL);
1394 g_free (uri);
1396 screen = gtk_widget_get_screen (GTK_WIDGET (parent));
1397 gdk_spawn_command_line_on_screen (screen, command, &error);
1398 if (error != NULL)
1400 g_warning ("Error executing help application: %s",
1401 error->message);
1402 g_error_free (error);
1404 return;
1406 g_free (command);
1410 * anjuta_utils_get_user_config_dir:
1412 * Returns a base directory in which to store user-specific application
1413 * configuration information such as user preferences and settings.
1415 * Return value: a new allocated string with the user config directory.
1417 gchar *
1418 anjuta_util_get_user_config_dir ()
1420 gchar *folder;
1422 folder = g_build_filename (g_get_user_config_dir (), "anjuta", NULL);
1424 if (!g_file_test (folder, G_FILE_TEST_IS_DIR))
1426 if (g_mkdir (folder, 755) == -1)
1428 g_warning ("There was an error creating the Anjuta config directory");
1429 g_free (folder);
1431 return NULL;
1435 return folder;
1438 /* The following functions are taken from gedit */
1440 /* Note that this function replace home dir with ~ */
1441 gchar *
1442 anjuta_util_uri_get_dirname (const gchar *uri)
1444 gchar *res;
1445 gchar *str;
1447 // CHECK: does it work with uri chaining? - Paolo
1448 str = g_path_get_dirname (uri);
1449 g_return_val_if_fail (str != NULL, ".");
1451 if ((strlen (str) == 1) && (*str == '.'))
1453 g_free (str);
1455 return NULL;
1458 res = anjuta_util_replace_home_dir_with_tilde (str);
1460 g_free (str);
1462 return res;
1465 gchar*
1466 anjuta_util_replace_home_dir_with_tilde (const gchar *uri)
1468 gchar *tmp;
1469 gchar *home;
1471 g_return_val_if_fail (uri != NULL, NULL);
1473 /* Note that g_get_home_dir returns a const string */
1474 tmp = (gchar *)g_get_home_dir ();
1476 if (tmp == NULL)
1477 return g_strdup (uri);
1479 home = g_filename_to_utf8 (tmp, -1, NULL, NULL, NULL);
1480 if (home == NULL)
1481 return g_strdup (uri);
1483 if (strcmp (uri, home) == 0)
1485 g_free (home);
1487 return g_strdup ("~");
1490 tmp = home;
1491 home = g_strdup_printf ("%s/", tmp);
1492 g_free (tmp);
1494 if (g_str_has_prefix (uri, home))
1496 gchar *res;
1498 res = g_strdup_printf ("~/%s", uri + strlen (home));
1500 g_free (home);
1502 return res;
1505 g_free (home);
1507 return g_strdup (uri);
1510 gchar *
1511 anjuta_util_str_middle_truncate (const gchar *string,
1512 guint truncate_length)
1514 GString *truncated;
1515 guint length;
1516 guint n_chars;
1517 guint num_left_chars;
1518 guint right_offset;
1519 guint delimiter_length;
1520 const gchar *delimiter = "\342\200\246";
1522 g_return_val_if_fail (string != NULL, NULL);
1524 length = strlen (string);
1526 g_return_val_if_fail (g_utf8_validate (string, length, NULL), NULL);
1528 /* It doesnt make sense to truncate strings to less than
1529 * the size of the delimiter plus 2 characters (one on each
1530 * side)
1532 delimiter_length = g_utf8_strlen (delimiter, -1);
1533 if (truncate_length < (delimiter_length + 2)) {
1534 return g_strdup (string);
1537 n_chars = g_utf8_strlen (string, length);
1539 /* Make sure the string is not already small enough. */
1540 if (n_chars <= truncate_length) {
1541 return g_strdup (string);
1544 /* Find the 'middle' where the truncation will occur. */
1545 num_left_chars = (truncate_length - delimiter_length) / 2;
1546 right_offset = n_chars - truncate_length + num_left_chars + delimiter_length;
1548 truncated = g_string_new_len (string,
1549 g_utf8_offset_to_pointer (string, num_left_chars) - string);
1550 g_string_append (truncated, delimiter);
1551 g_string_append (truncated, g_utf8_offset_to_pointer (string, right_offset));
1553 return g_string_free (truncated, FALSE);