3 * A Nautilus extension which offers configurable context menu actions.
5 * Copyright (C) 2005 The GNOME Foundation
6 * Copyright (C) 2006, 2007, 2008 Frederic Ruaudel and others (see AUTHORS)
7 * Copyright (C) 2009, 2010, 2011 Pierre Wieser and others (see AUTHORS)
9 * This Program is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU General Public License as
11 * published by the Free Software Foundation; either version 2 of
12 * the License, or (at your option) any later version.
14 * This Program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public
20 * License along with this Library; see the file COPYING. If not,
21 * write to the Free Software Foundation, Inc., 59 Temple Place,
22 * Suite 330, Boston, MA 02111-1307, USA.
25 * Frederic Ruaudel <grumz@grumz.net>
26 * Rodrigo Moya <rodrigo@gnome-db.org>
27 * Pierre Wieser <pwieser@trychlos.org>
28 * ... and many others (see AUTHORS)
40 #include <glib/gstdio.h>
42 #include <api/na-core-utils.h>
44 #include "na-iabout.h"
46 static GSList
*text_to_string_list( const gchar
*text
, const gchar
*separator
, const gchar
*default_value
);
47 static gboolean
info_dir_is_writable( GFile
*file
, const gchar
*path
);
50 * na_core_utils_boolean_from_string
51 * @string: a string to be converted.
53 * Returns: %TRUE if the string evaluates to "true" (case insensitive),
59 na_core_utils_boolean_from_string( const gchar
*string
)
61 return( g_ascii_strcasecmp( string
, "true" ) == 0 );
65 * na_core_utils_str_add_prefix:
66 * @prefix: the prefix to be prepended.
67 * @str: a multiline string.
69 * Appends a prefix to each line of the string.
71 * Returns: a new string which should be g_free() by the caller.
76 na_core_utils_str_add_prefix( const gchar
*prefix
, const gchar
*str
)
81 list
= text_to_string_list( str
, "\n", NULL
);
82 result
= g_string_new( "" );
84 for( il
= list
; il
; il
= il
->next
){
85 g_string_append_printf( result
, "%s%s\n", prefix
, ( gchar
* ) il
->data
);
88 na_core_utils_slist_free( list
);
90 return( g_string_free( result
, FALSE
));
94 * na_core_utils_str_collate:
95 * @str1: an UTF-8 encoded string.
96 * @str2: an UTF-8 encoded string.
101 * <para>-1 if str1 < str2,</para>
104 * <para>0 if str1 = str2,</para>
107 * <para>+1 if str1 > str2.</para>
114 na_core_utils_str_collate( const gchar
*str1
, const gchar
*str2
)
119 res
= g_utf8_collate( str1
, str2
);
121 } else if( !str1
&& !str2
){
128 g_return_val_if_fail( str2
== NULL
, 0 );
135 * na_core_utils_str_remove_char:
136 * @string: source string.
137 * @to_remove: the character to remove.
139 * Returns: a newly allocated string, which is a copy of the source @string,
140 * minus all the found occurrences of the given @to_remove char.
142 * The returned string should be g_free() by the caller.
147 na_core_utils_str_remove_char( const gchar
*string
, const gchar
*to_remove
)
149 static const gchar
*thisfn
= "na_core_utils_str_remove_char";
154 removed
= g_strdup( string
);
156 if( g_utf8_validate( string
, -1, NULL
)){
159 regex
= g_regex_new( to_remove
, 0, 0, &error
);
161 g_warning( "%s [g_regex_new] %s", thisfn
, error
->message
);
162 g_error_free( error
);
166 removed
= g_regex_replace_literal( regex
, string
, -1, 0, "", 0, &error
);
168 g_warning( "%s [g_regex_replace_literal] %s", thisfn
, error
->message
);
169 g_error_free( error
);
178 * na_core_utils_str_remove_suffix:
179 * @string: source string.
180 * @suffix: suffix to be removed from @string.
182 * Returns: a newly allocated string, which is a copy of the source @string,
183 * minus the removed @suffix if present. If @strings doesn't terminate with
184 * @suffix, then the returned string is equal to source @string.
186 * The returned string should be g_free() by the caller.
191 na_core_utils_str_remove_suffix( const gchar
*string
, const gchar
*suffix
)
196 removed
= g_strdup( string
);
198 if( g_str_has_suffix( string
, suffix
)){
199 ptr
= g_strrstr( removed
, suffix
);
207 * na_core_utils_str_split_first_word:
208 * @string: a space-separated string.
209 * @first: a pointer to a gchar *.
210 * @other: a pointer to a gchar *.
212 * Split the @string string into two components:
215 * <para>the first word which is allocated in @first,</para>
218 * <para>the rest of the string which is allocated in @other.</para>
222 * The two allocated strings should be g_free() by the caller.
227 na_core_utils_str_split_first_word( const gchar
*string
, gchar
**first
, gchar
**other
)
229 gchar
**splitted
, **iter
;
239 if( string
&& g_utf8_strlen( string
, -1 )){
240 splitted
= g_strsplit( string
, " ", 2 );
243 *first
= g_strdup( *iter
);
247 *other
= g_strdup( *iter
);
249 g_strfreev( splitted
);
254 na_core_utils_slist_add_message( GSList
**messages
, const gchar
*format
, ... )
259 va_start( va
, format
);
260 tmp
= g_markup_vprintf_escaped( format
, va
);
263 *messages
= g_slist_append( *messages
, tmp
);
267 * na_core_utils_slist_duplicate:
268 * @slist: the #GSList to be duplicated.
270 * Returns: a #GSList of strings.
272 * The returned list should be na_core_utils_slist_free() by the caller.
277 na_core_utils_slist_duplicate( GSList
*slist
)
279 GSList
*dest_slist
, *it
;
283 for( it
= slist
; it
!= NULL
; it
= it
->next
){
284 dest_slist
= g_slist_prepend( dest_slist
, g_strdup(( gchar
* ) it
->data
) );
287 dest_slist
= g_slist_reverse( dest_slist
);
289 return( dest_slist
);
293 * na_core_utils_slist_dump:
294 * @prefix: a string to be used as a prefix for each outputed line.
295 * @list: a list of strings.
297 * Dumps the content of a list of strings.
302 na_core_utils_slist_dump( const gchar
*prefix
, GSList
*list
)
304 static const gchar
*thisfn
= "na_core_utils_slist_dump";
307 const gchar
*thispfx
;
309 thispfx
= ( prefix
&& strlen( prefix
)) ? prefix
: thisfn
;
311 g_debug( "%s: list at %p has %d element(s)", thispfx
, ( void * ) list
, g_slist_length( list
));
313 for( i
=list
, c
=0 ; i
; i
=i
->next
){
314 g_debug( "%s: [%2d] %s (%lu)",
315 thispfx
, c
++, ( gchar
* ) i
->data
, g_utf8_strlen( ( gchar
* ) i
->data
, -1 ));
320 * na_core_utils_slist_from_split:
321 * @text: a string to be splitted.
322 * @separator: the string to be used as the separator.
324 * Returns: a #GSList with the list of strings after having been splitted.
326 * The returned #GSList should be na_core_utils_slist_free() by the caller.
331 na_core_utils_slist_from_split( const gchar
*text
, const gchar
*separator
)
341 source
= g_strdup( text
);
342 tmp
= g_strstrip( source
);
344 if( !g_utf8_strlen( tmp
, -1 )){
348 tokens
= g_strsplit( tmp
, separator
, -1 );
349 slist
= na_core_utils_slist_from_array(( const gchar
** ) tokens
);
350 g_strfreev( tokens
);
358 * na_core_utils_slist_from_array:
359 * @str_array: an NULL-terminated array of strings.
361 * Returns: a #GSList list of strings, which should be #na_core_utils_slist_free()
367 na_core_utils_slist_from_array( const gchar
**str_array
)
373 idx
= ( gchar
** ) str_array
;
376 slist
= g_slist_prepend( slist
, g_strstrip( g_strdup( *idx
)));
380 return( g_slist_reverse( slist
));
384 * na_core_utils_slist_join_at_end:
385 * @slist: the string list to join.
386 * @link: the string used to join each element.
388 * Returns: a newly allocated string which should be g_free() by the caller.
393 na_core_utils_slist_join_at_end( GSList
*slist
, const gchar
*link
)
398 str
= g_string_new( "" );
400 for( is
= slist
; is
; is
= is
->next
){
402 g_string_append_printf( str
, "%s", link
);
404 g_string_append_printf( str
, "%s", ( const gchar
* ) is
->data
);
407 return( g_string_free( str
, FALSE
));
411 * na_core_utils_slist_remove_ascii:
412 * @slist: the #GSList to be updated.
413 * @text: string to remove.
415 * Removes a string from a GSList of strings.
417 * Returns: the same, updated, @slist.
422 na_core_utils_slist_remove_ascii( GSList
*slist
, const gchar
*text
)
426 for( il
= slist
; il
; il
= il
->next
){
428 const gchar
*istr
= ( const gchar
* ) il
->data
;
429 if( !g_ascii_strcasecmp( text
, istr
)){
431 slist
= g_slist_remove( slist
, ( gconstpointer
) istr
);
440 * na_core_utils_slist_remove_utf8:
441 * @slist: the #GSList to be updated.
442 * @text: the string to be removed.
444 * Removes from the @slist the item which has a string which is equal to
447 * Returns: the new @slist start position.
452 na_core_utils_slist_remove_utf8( GSList
*slist
, const gchar
*text
)
456 for( is
= slist
; is
; is
= is
->next
){
457 const gchar
*istr
= ( const gchar
* ) is
->data
;
458 if( !na_core_utils_str_collate( text
, istr
)){
460 slist
= g_slist_delete_link( slist
, is
);
469 * na_core_utils_slist_to_array:
470 * @slist: a list of strings.
472 * Returns: a newly allocated array of strings, which should be
473 * g_strfreev() by the caller.
478 na_core_utils_slist_to_array( GSList
*slist
)
484 str
= g_string_new( "" );
485 for( is
= slist
; is
; is
= is
->next
){
486 g_string_append_printf( str
, "%s;", ( const gchar
* ) is
->data
);
488 array
= g_strsplit( str
->str
, ";", -1 );
489 g_string_free( str
, TRUE
);
495 * na_core_utils_slist_to_text:
496 * @slist: a list of strings.
498 * Concatenates a string list to a semi-colon-separated text
499 * suitable for an entry in the user interface
501 * Returns: a newly allocated string, which should be g_free() by the
507 na_core_utils_slist_to_text( GSList
*slist
)
511 gchar
*text
= g_strdup( "" );
513 for( ib
= slist
; ib
; ib
= ib
->next
){
515 tmp
= g_strdup_printf( "%s; ", text
);
519 tmp
= g_strdup_printf( "%s%s", text
, ( gchar
* ) ib
->data
);
528 * na_core_utils_slist_setup_element:
529 * @list: the GSList of strings to be setup.
530 * @element: the string to add to or remove of the list.
531 * @set: whether the @element should be set or removed.
533 * Setup the @list so that the @element is once in the @list if @set is %TRUE,
534 * or not if @set is %FALSE.
536 * Returns: the updated @list.
541 na_core_utils_slist_setup_element( GSList
*list
, const gchar
*element
, gboolean set
)
545 count
= na_core_utils_slist_count( list
, element
);
547 if( set
&& count
== 0 ){
548 list
= g_slist_prepend( list
, g_strdup( element
));
550 if( !set
&& count
> 0 ){
551 list
= na_core_utils_slist_remove_ascii( list
, element
);
558 * na_core_utils_slist_count:
559 * @list: the GSList of strings to be searched.
560 * @str: the searched string.
562 * Search for a string in a string list.
564 * Returns: the count of @ßtr in @list list.
569 na_core_utils_slist_count( GSList
*list
, const gchar
*str
)
576 for( il
= list
; il
; il
= il
->next
){
577 const gchar
*istr
= ( const gchar
* ) il
->data
;
578 if( !na_core_utils_str_collate( str
, istr
)){
587 * na_core_utils_slist_find_negated:
588 * @list: the GSList of strings to be searched.
589 * @str: the searched string.
591 * Search for a string in a string list which may contain nagated items.
593 * Returns: %TRUE if the string has been found in list.
598 na_core_utils_slist_find_negated( GSList
*list
, const gchar
*str
)
602 for( il
= list
; il
; il
= il
->next
){
603 const gchar
*istr
= g_strstrip( g_strdup( ( const gchar
* ) il
->data
));
605 if( istr
[0] == '!' ){
606 gchar
*istrdup
= g_strdup( istr
+1 );
607 int match
= na_core_utils_str_collate( str
, istrdup
);
613 } else if( na_core_utils_str_collate( str
, istr
) == 0 ){
622 * na_core_utils_slist_are_equal:
623 * @a: a GSList of strings.
624 * @b: another GSList of strings to be compared with @first.
626 * Compare two string lists, without regards to the order.
628 * Returns: %TRUE if the two lists have same content.
633 na_core_utils_slist_are_equal( GSList
*a
, GSList
*b
)
637 for( il
= a
; il
; il
= il
->next
){
638 const gchar
*str
= ( const gchar
* ) il
->data
;
639 if( na_core_utils_slist_count( b
, str
) == 0 ){
644 for( il
= b
; il
; il
= il
->next
){
645 const gchar
*str
= ( const gchar
* ) il
->data
;
646 if( na_core_utils_slist_count( a
, str
) == 0 ){
655 * na_core_utils_slist_free:
656 * @slist: a #GSList list of strings.
658 * Releases the strings and the list itself.
663 na_core_utils_slist_free( GSList
*slist
)
665 g_slist_foreach( slist
, ( GFunc
) g_free
, NULL
);
666 g_slist_free( slist
);
670 * na_core_utils_gstring_joinv:
671 * @start: a prefix to be written at the beginning of the output string.
672 * @separator: a string to be used as separator.
673 * @list: the list of strings to be concatenated.
675 * Concatenates a gchar **list of strings to a new string.
677 * Returns: a newly allocated string which should be g_free() by the caller.
682 na_core_utils_gstring_joinv( const gchar
*start
, const gchar
*separator
, gchar
**list
)
684 GString
*tmp_string
= g_string_new( "" );
687 g_return_val_if_fail( list
!= NULL
, NULL
);
690 tmp_string
= g_string_append( tmp_string
, start
);
693 if( list
[0] != NULL
){
694 tmp_string
= g_string_append( tmp_string
, list
[0] );
697 for( i
= 1 ; list
[i
] != NULL
; i
++ ){
699 tmp_string
= g_string_append( tmp_string
, separator
);
701 tmp_string
= g_string_append( tmp_string
, list
[i
] );
704 return( g_string_free( tmp_string
, FALSE
));
708 * split a text buffer in lines
711 text_to_string_list( const gchar
*text
, const gchar
*separator
, const gchar
*default_value
)
713 GSList
*strlist
= NULL
;
716 gchar
*source
= g_strdup( text
);
718 tmp
= g_strstrip( source
);
719 if( !strlen( tmp
) && default_value
){
720 strlist
= g_slist_append( strlist
, g_strdup( default_value
));
723 tokens
= g_strsplit( source
, separator
, -1 );
724 strlist
= na_core_utils_slist_from_array(( const gchar
** ) tokens
);
725 g_strfreev( tokens
);
733 * na_core_utils_selcount_get_ope:
734 * @selcount: the selection count condition string.
735 * @ope: a pointer to a newly allocated string which will contains the
737 * @uint: a pointer to a newly allocated string which will contains the
740 * Parses a selection count string, and extract the operation code and the
743 * The two returned strings must be g_free() by the caller.
748 na_core_utils_selcount_get_ope_int( const gchar
*selcount
, gchar
**ope
, gchar
**uint
)
753 g_return_if_fail( ope
&& uint
);
758 dup
= g_strstrip( g_strdup( selcount
));
759 *ope
= g_strdup( " " );
762 dup2
= g_strstrip( g_strdup( dup
+1 ));
763 uint_int
= abs( atoi( dup2
));
764 *uint
= g_strdup_printf( "%d", uint_int
);
771 * na_core_utils_dir_is_writable_path:
772 * @path: the path of the directory to be tested.
774 * Returns: %TRUE if the directory is writable, %FALSE else.
776 * Please note that this type of test is subject to race conditions,
777 * as the directory may become unwritable after a successful test,
778 * but before the caller has been able to actually write into it.
780 * There is no "super-test". Just try...
785 na_core_utils_dir_is_writable_path( const gchar
*path
)
787 static const gchar
*thisfn
= "na_core_utils_path_is_writable";
791 if( !path
|| !g_utf8_strlen( path
, -1 )){
792 g_warning( "%s: empty path", thisfn
);
796 file
= g_file_new_for_path( path
);
797 writable
= info_dir_is_writable( file
, path
);
798 g_object_unref( file
);
804 * na_core_utils_dir_is_writable_uri:
805 * @uri: the URI of the directory to be tested.
807 * Returns: %TRUE if the directory is writable, %FALSE else.
809 * Please note that this type of test is subject to race conditions,
810 * as the directory may become unwritable after a successful test,
811 * but before the caller has been able to actually write into it.
813 * There is no "super-test". Just try...
818 na_core_utils_dir_is_writable_uri( const gchar
*uri
)
820 static const gchar
*thisfn
= "na_core_utils_dir_is_writable_uri";
824 if( !uri
|| !g_utf8_strlen( uri
, -1 )){
825 g_warning( "%s: empty uri", thisfn
);
829 file
= g_file_new_for_uri( uri
);
830 writable
= info_dir_is_writable( file
, uri
);
831 g_object_unref( file
);
837 info_dir_is_writable( GFile
*file
, const gchar
*path_or_uri
)
839 static const gchar
*thisfn
= "na_core_utils_info_dir_is_writable";
840 GError
*error
= NULL
;
845 info
= g_file_query_info( file
,
846 G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE
"," G_FILE_ATTRIBUTE_STANDARD_TYPE
,
847 G_FILE_QUERY_INFO_NONE
, NULL
, &error
);
850 if( error
->code
!= G_IO_ERROR_NOT_FOUND
){
851 g_warning( "%s: g_file_query_info error: %s", thisfn
, error
->message
);
853 g_error_free( error
);
857 type
= g_file_info_get_file_type( info
);
858 if( type
!= G_FILE_TYPE_DIRECTORY
){
859 g_debug( "%s: %s is not a directory", thisfn
, path_or_uri
);
860 g_object_unref( info
);
864 writable
= g_file_info_get_attribute_boolean( info
, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE
);
866 g_debug( "%s: %s is not writable", thisfn
, path_or_uri
);
869 g_object_unref( info
);
875 * na_core_utils_dir_split_ext:
876 * @string: the input path or URI to be splitted.
877 * @first: a pointer to a buffer which will contain the first part of the split.
878 * @ext: a pointer to a buffer which will contain the extension part of the path.
880 * Split the given @string, returning the first part and the extension in newly
881 * allocated buffers which should be g_free() by the caller.
883 * The extension is set to an empty string if no extension is detected.
888 na_core_utils_dir_split_ext( const gchar
*string
, gchar
**first
, gchar
**ext
)
891 gchar
**array
, **iter
;
893 dupped
= g_strreverse( g_strdup( string
));
894 array
= g_strsplit( dupped
, ".", 2 );
896 if( g_strv_length( array
) == 1 ){
898 *ext
= g_strdup( "" );
901 *first
= g_strreverse( g_strdup(( const gchar
* ) *array
));
905 *ext
= g_strreverse( g_strdup(( const gchar
* ) *array
));
910 *first
= g_strreverse( g_strdup(( const gchar
* ) *iter
));
919 * na_core_utils_file_delete:
920 * @path: the path of the file to be deleted.
922 * Returns: %TRUE if the file is successfully deleted, %FALSE else.
927 na_core_utils_file_delete( const gchar
*path
)
929 static const gchar
*thisfn
= "na_core_utils_file_delete";
930 gboolean deleted
= FALSE
;
932 if( !path
|| !g_utf8_strlen( path
, -1 )){
936 if( g_unlink( path
) == 0 ){
940 g_warning( "%s: %s: %s", thisfn
, path
, g_strerror( errno
));
947 * na_core_utils_file_exists:
950 * Returns: %TRUE if the specified file exists, %FALSE else.
952 * Race condition: cf. na_core_utils_dir_is_writable_path() and
953 * na_core_utils_dir_is_writable_uri() comments.
958 na_core_utils_file_exists( const gchar
*uri
)
963 file
= g_file_new_for_uri( uri
);
964 exists
= g_file_query_exists( file
, NULL
);
965 g_object_unref( file
);
971 * na_core_utils_file_load_from_uri:
972 * @uri: the URI the file must be loaded from.
973 * @length: a pointer to the length of the read content.
975 * Loads the file into a newly allocated buffer, and set up the length of the
976 * read content if not %NULL.
978 * Returns: the newly allocated buffer which contains the file content, or %NULL.
979 * This buffer should be g_free() by the caller.
984 na_core_utils_file_load_from_uri( const gchar
*uri
, gsize
*length
)
989 file
= g_file_new_for_uri( uri
);
991 if( !g_file_load_contents( file
, NULL
, &data
, length
, NULL
, NULL
)){
999 g_object_unref( file
);
1005 * na_core_utils_print_version:
1007 * Print a version message on the console
1010 * nautilus-actions-new (Nautilus-Actions) v 2.29.1
1011 * Copyright (C) 2005-2007 Frederic Ruaudel
1012 * Copyright (C) 2009, 2010, 2011 Pierre Wieser
1013 * Nautilus-Actions is free software, licensed under GPLv2 or later.
1019 na_core_utils_print_version( void )
1024 g_print( "%s (%s) v %s\n", g_get_prgname(), PACKAGE_NAME
, PACKAGE_VERSION
);
1025 copyright
= na_iabout_get_copyright( TRUE
);
1026 g_print( "%s\n", copyright
);
1027 g_free( copyright
);
1029 g_print( "%s is free software, and is provided without any warranty. You may\n", PACKAGE_NAME
);
1030 g_print( "redistribute copies of %s under the terms of the GNU General Public\n", PACKAGE_NAME
);
1031 g_print( "License (see COPYING).\n" );
1034 g_debug( "Program has been compiled against Glib %d.%d.%d, Gtk+ %d.%d.%d",
1035 GLIB_MAJOR_VERSION
, GLIB_MINOR_VERSION
, GLIB_MICRO_VERSION
,
1036 GTK_MAJOR_VERSION
, GTK_MINOR_VERSION
, GTK_MICRO_VERSION
);
1038 g_debug( "Current system runs Glib %d.%d.%d, Gtk+ %d.%d.%d\n",
1039 glib_major_version
, glib_minor_version
, glib_micro_version
,
1040 gtk_major_version
, gtk_minor_version
, gtk_micro_version
);