README: add deprecation notice
[nautilus-actions.git] / src / core / fma-core-utils.c
bloba3d526a797143556b3521fb74159840bb9379eab
1 /*
2 * FileManager-Actions
3 * A file-manager extension which offers configurable context menu actions.
5 * Copyright (C) 2005 The GNOME Foundation
6 * Copyright (C) 2006-2008 Frederic Ruaudel and others (see AUTHORS)
7 * Copyright (C) 2009-2015 Pierre Wieser and others (see AUTHORS)
9 * FileManager-Actions 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 * FileManager-Actions 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 GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with FileManager-Actions; see the file COPYING. If not, see
21 * <http://www.gnu.org/licenses/>.
23 * Authors:
24 * Frederic Ruaudel <grumz@grumz.net>
25 * Rodrigo Moya <rodrigo@gnome-db.org>
26 * Pierre Wieser <pwieser@trychlos.org>
27 * ... and many others (see AUTHORS)
30 #ifdef HAVE_CONFIG_H
31 #include <config.h>
32 #endif
34 #include <errno.h>
35 #include <stdlib.h>
36 #include <string.h>
38 #include <gio/gio.h>
39 #include <glib/gstdio.h>
41 #include <api/fma-core-utils.h>
43 #include "fma-about.h"
45 /* minimal and maximal size for loading the content of a file in memory
46 * used by fma_core_utils_file_is_size_ok()
48 #define SIZE_MIN 1
49 #define SIZE_MAX 1048576 /* 1 MB */
51 #ifdef FMA_ENABLE_DEPRECATED
52 static GSList *text_to_string_list( const gchar *text, const gchar *separator, const gchar *default_value );
53 #endif
54 static gboolean info_dir_is_writable( GFile *file, const gchar *path );
55 static gboolean file_is_loadable( GFile *file );
56 static void list_perms( const gchar *path, const gchar *message, const gchar *command );
58 /**
59 * fma_core_utils_boolean_from_string
60 * @string: a string to be converted.
62 * Returns: %TRUE if the string evaluates to "true" (case insensitive),
63 * %FALSE else.
65 * Since: 2.30
67 gboolean
68 fma_core_utils_boolean_from_string( const gchar *string )
70 if( !string ) return( FALSE );
72 return( g_ascii_strcasecmp( string, "true" ) == 0 || atoi( string ) != 0 );
75 #ifdef FMA_ENABLE_DEPRECATED
76 /**
77 * fma_core_utils_str_add_prefix:
78 * @prefix: the prefix to be prepended.
79 * @str: a multiline string.
81 * Appends a prefix to each line of the string.
83 * Returns: a new string which should be g_free() by the caller.
85 * Since: 2.30
86 * Deprecated: 3.2
88 gchar *
89 fma_core_utils_str_add_prefix( const gchar *prefix, const gchar *str )
91 GSList *list, *il;
92 GString *result;
94 list = text_to_string_list( str, "\n", NULL );
95 result = g_string_new( "" );
97 for( il = list ; il ; il = il->next ){
98 g_string_append_printf( result, "%s%s\n", prefix, ( gchar * ) il->data );
101 fma_core_utils_slist_free( list );
103 return( g_string_free( result, FALSE ));
107 * split a text buffer in lines
109 static GSList *
110 text_to_string_list( const gchar *text, const gchar *separator, const gchar *default_value )
112 GSList *strlist = NULL;
113 gchar **tokens;
114 gchar *tmp;
115 gchar *source = g_strdup( text );
117 tmp = g_strstrip( source );
118 if( !strlen( tmp ) && default_value ){
119 strlist = g_slist_append( strlist, g_strdup( default_value ));
121 } else {
122 tokens = g_strsplit( source, separator, -1 );
123 strlist = fma_core_utils_slist_from_array(( const gchar ** ) tokens );
124 g_strfreev( tokens );
127 g_free( source );
128 return( strlist );
130 #endif /* FMA_ENABLE_DEPRECATED */
133 * fma_core_utils_str_collate:
134 * @str1: an UTF-8 encoded string.
135 * @str2: an UTF-8 encoded string.
137 * Returns:
138 * <itemizedlist>
139 * <listitem>
140 * <para>-1 if str1 < str2,</para>
141 * </listitem>
142 * <listitem>
143 * <para>0 if str1 = str2,</para>
144 * </listitem>
145 * <listitem>
146 * <para>+1 if str1 > str2.</para>
147 * </listitem>
148 * </itemizedlist>
150 * Since: 2.30
153 fma_core_utils_str_collate( const gchar *str1, const gchar *str2 )
155 int res;
157 if( str1 && str2 ){
158 res = g_utf8_collate( str1, str2 );
160 } else if( !str1 && !str2 ){
161 res = 0;
163 } else if( !str1 ){
164 res = -1;
166 } else {
167 g_return_val_if_fail( str2 == NULL, 0 );
168 res = 1;
170 return( res );
174 * fma_core_utils_str_remove_char:
175 * @string: source string.
176 * @to_remove: the character to remove.
178 * Returns: a newly allocated string, which is a copy of the source @string,
179 * minus all the found occurrences of the given @to_remove char.
181 * The returned string should be g_free() by the caller.
183 * Since: 2.30
185 gchar *
186 fma_core_utils_str_remove_char( const gchar *string, const gchar *to_remove )
188 static const gchar *thisfn = "fma_core_utils_str_remove_char";
189 gchar *removed;
190 GRegex *regex;
191 GError *error;
193 removed = g_strdup( string );
195 if( g_utf8_validate( string, -1, NULL )){
197 error = NULL;
198 regex = g_regex_new( to_remove, 0, 0, &error );
199 if( error ){
200 g_warning( "%s [g_regex_new] %s", thisfn, error->message );
201 g_error_free( error );
203 } else {
204 g_free( removed );
205 removed = g_regex_replace_literal( regex, string, -1, 0, "", 0, &error );
206 if( error ){
207 g_warning( "%s [g_regex_replace_literal] %s", thisfn, error->message );
208 g_error_free( error );
213 return( removed );
217 * fma_core_utils_str_remove_suffix:
218 * @string: source string.
219 * @suffix: suffix to be removed from @string.
221 * Returns: a newly allocated string, which is a copy of the source @string,
222 * minus the removed @suffix if present. If @strings doesn't terminate with
223 * @suffix, then the returned string is equal to source @string.
225 * The returned string should be g_free() by the caller.
227 * Since: 2.30
229 gchar *
230 fma_core_utils_str_remove_suffix( const gchar *string, const gchar *suffix )
232 gchar *removed;
233 gchar *ptr;
235 removed = g_strdup( string );
237 if( g_str_has_suffix( string, suffix )){
238 ptr = g_strrstr( removed, suffix );
239 ptr[0] = '\0';
242 return( removed );
246 * fma_core_utils_str_split_first_word:
247 * @string: a space-separated string.
248 * @first: a pointer to a gchar *.
249 * @other: a pointer to a gchar *.
251 * Split the @string string into two components:
252 * <itemizedlist>
253 * <listitem>
254 * <para>the first word which is allocated in @first,</para>
255 * </listitem>
256 * <listitem>
257 * <para>the rest of the string which is allocated in @other.</para>
258 * </listitem>
259 * </itemizedlist>
261 * The two allocated strings should be g_free() by the caller.
263 * Since: 2.30
265 void
266 fma_core_utils_str_split_first_word( const gchar *string, gchar **first, gchar **other )
268 gchar **splitted, **iter;
270 if( first ){
271 *first = NULL;
274 if( other ){
275 *other = NULL;
278 if( string && g_utf8_strlen( string, -1 )){
279 splitted = g_strsplit( string, " ", 2 );
280 iter = splitted;
281 if( first ){
282 *first = g_strdup( *iter );
284 iter++;
285 if( other ){
286 *other = g_strdup( *iter );
288 g_strfreev( splitted );
293 * fma_core_utils_str_subst:
294 * @pattern: the pattern.
295 * @key: the key string to be substituted.
296 * @subst: the string which will replace @key.
298 * Returns:
299 * a copy of @pattern where the first occurrence of @key has been
300 * substituted with @subst, as a newly allocated string which should be
301 * g_free() by the caller,
302 * or a copy of @pattern if @key is not found in @pattern.
304 gchar *
305 fma_core_utils_str_subst( const gchar *pattern, const gchar *key, const gchar *subst )
307 GString *result;
308 gchar *found;
310 result = g_string_new( "" );
311 found = g_strstr_len( pattern, -1, key );
312 if( found ){
313 result = g_string_append_len( result, pattern, ( gssize )( found - pattern ));
314 result = g_string_append( result, subst );
315 result = g_string_append( result, found + g_utf8_strlen( key, -1 ));
317 } else {
318 result = g_string_append( result, pattern );
321 return( g_string_free( result, FALSE ));
324 void
325 fma_core_utils_slist_add_message( GSList **messages, const gchar *format, ... )
327 va_list va;
328 gchar *tmp;
330 va_start( va, format );
331 tmp = g_markup_vprintf_escaped( format, va );
332 va_end( va );
334 *messages = g_slist_append( *messages, tmp );
338 * fma_core_utils_slist_duplicate:
339 * @slist: the #GSList to be duplicated.
341 * Returns: a #GSList of strings.
343 * The returned list should be fma_core_utils_slist_free() by the caller.
345 * Since: 2.30
347 GSList *
348 fma_core_utils_slist_duplicate( GSList *slist )
350 GSList *dest_slist, *it;
352 dest_slist = NULL;
354 for( it = slist ; it != NULL ; it = it->next ){
355 dest_slist = g_slist_prepend( dest_slist, g_strdup(( gchar * ) it->data ) );
358 dest_slist = g_slist_reverse( dest_slist );
360 return( dest_slist );
364 * fma_core_utils_slist_dump:
365 * @prefix: a string to be used as a prefix for each outputed line.
366 * @list: a list of strings.
368 * Dumps the content of a list of strings.
370 * Since: 2.30
372 void
373 fma_core_utils_slist_dump( const gchar *prefix, GSList *list )
375 static const gchar *thisfn = "fma_core_utils_slist_dump";
376 GSList *i;
377 int c;
378 const gchar *thispfx;
380 thispfx = ( prefix && strlen( prefix )) ? prefix : thisfn;
382 g_debug( "%s: list at %p has %d element(s)", thispfx, ( void * ) list, g_slist_length( list ));
384 for( i=list, c=0 ; i ; i=i->next ){
385 g_debug( "%s: [%2d] %s (%lu)",
386 thispfx, c++, ( gchar * ) i->data, g_utf8_strlen( ( gchar * ) i->data, -1 ));
391 * fma_core_utils_slist_from_split:
392 * @text: a string to be splitted.
393 * @separator: the string to be used as the separator.
395 * Returns: a #GSList with the list of strings after having been splitted.
397 * The returned #GSList should be fma_core_utils_slist_free() by the caller.
399 * Since: 2.30
401 GSList *
402 fma_core_utils_slist_from_split( const gchar *text, const gchar *separator )
404 GSList *slist;
405 gchar **tokens;
406 gchar *source, *tmp;
408 if( !text ){
409 return( NULL );
412 source = g_strdup( text );
413 tmp = g_strstrip( source );
415 if( !g_utf8_strlen( tmp, -1 )){
416 return( NULL );
419 tokens = g_strsplit( tmp, separator, -1 );
420 slist = fma_core_utils_slist_from_array(( const gchar ** ) tokens );
421 g_strfreev( tokens );
423 g_free( source );
425 return( slist );
429 * fma_core_utils_slist_from_array:
430 * @str_array: an NULL-terminated array of strings.
432 * Returns: a #GSList list of strings, which should be #fma_core_utils_slist_free()
433 * by the caller.
435 * Since: 2.30
437 GSList *
438 fma_core_utils_slist_from_array( const gchar **str_array )
440 GSList *slist;
441 gchar **idx;
443 slist = NULL;
444 idx = ( gchar ** ) str_array;
446 while( *idx ){
447 slist = g_slist_prepend( slist, g_strstrip( g_strdup( *idx )));
448 idx++;
451 return( g_slist_reverse( slist ));
455 * fma_core_utils_slist_join_at_end:
456 * @slist: the string list to join.
457 * @link: the string used to join each element.
459 * Returns: a newly allocated string which should be g_free() by the caller.
461 * Since: 2.30
463 gchar *
464 fma_core_utils_slist_join_at_end( GSList *slist, const gchar *link )
466 GSList *is;
467 GString *str;
469 str = g_string_new( "" );
471 for( is = slist ; is ; is = is->next ){
472 if( str->len ){
473 g_string_append_printf( str, "%s", link );
475 g_string_append_printf( str, "%s", ( const gchar * ) is->data );
478 return( g_string_free( str, FALSE ));
482 * fma_core_utils_slist_remove_ascii:
483 * @slist: the #GSList to be updated.
484 * @text: string to remove.
486 * Removes a string from a GSList of strings.
488 * Returns: the same, updated, @slist.
490 * Since: 2.30
492 GSList *
493 fma_core_utils_slist_remove_ascii( GSList *slist, const gchar *text )
495 GSList *il;
497 for( il = slist ; il ; il = il->next ){
499 const gchar *istr = ( const gchar * ) il->data;
500 if( !g_ascii_strcasecmp( text, istr )){
502 slist = g_slist_remove( slist, ( gconstpointer ) istr );
503 return( slist );
507 return( slist );
511 * fma_core_utils_slist_remove_utf8:
512 * @slist: the #GSList to be updated.
513 * @text: the string to be removed.
515 * Removes from the @slist the item which has a string which is equal to
516 * @text.
518 * Returns: the new @slist start position.
520 * Since: 2.30
522 GSList *
523 fma_core_utils_slist_remove_utf8( GSList *slist, const gchar *text )
525 GSList *is;
527 for( is = slist ; is ; is = is->next ){
528 const gchar *istr = ( const gchar * ) is->data;
529 if( !fma_core_utils_str_collate( text, istr )){
530 g_free( is->data );
531 slist = g_slist_delete_link( slist, is );
532 break;
536 return( slist );
540 * fma_core_utils_slist_to_array:
541 * @slist: a list of strings.
543 * Returns: a newly allocated array of strings, which should be
544 * g_strfreev() by the caller.
546 * Since: 2.30
548 gchar **
549 fma_core_utils_slist_to_array( GSList *slist )
551 GString *str;
552 GSList *is;
553 gchar **array;
555 str = g_string_new( "" );
556 for( is = slist ; is ; is = is->next ){
557 g_string_append_printf( str, "%s;", ( const gchar * ) is->data );
559 array = g_strsplit( str->str, ";", -1 );
560 g_string_free( str, TRUE );
562 return( array );
566 * fma_core_utils_slist_to_text:
567 * @slist: a list of strings.
569 * Concatenates a string list to a semi-colon-separated text
570 * suitable for an entry in the user interface
572 * Returns: a newly allocated string, which should be g_free() by the
573 * caller.
575 * Since: 2.30
577 gchar *
578 fma_core_utils_slist_to_text( GSList *slist )
580 GSList *ib;
581 gchar *tmp;
582 gchar *text = g_strdup( "" );
584 for( ib = slist ; ib ; ib = ib->next ){
585 if( strlen( text )){
586 tmp = g_strdup_printf( "%s; ", text );
587 g_free( text );
588 text = tmp;
590 tmp = g_strdup_printf( "%s%s", text, ( gchar * ) ib->data );
591 g_free( text );
592 text = tmp;
595 return( text );
599 * fma_core_utils_slist_setup_element:
600 * @list: the GSList of strings to be setup.
601 * @element: the string to add to or remove of the list.
602 * @set: whether the @element should be set or removed.
604 * Setup the @list so that the @element is once in the @list if @set is %TRUE,
605 * or not if @set is %FALSE.
607 * Returns: the updated @list.
609 * Since: 2.30
611 GSList *
612 fma_core_utils_slist_setup_element( GSList *list, const gchar *element, gboolean set )
614 guint count;
616 count = fma_core_utils_slist_count( list, element );
618 if( set && count == 0 ){
619 list = g_slist_prepend( list, g_strdup( element ));
621 if( !set && count > 0 ){
622 list = fma_core_utils_slist_remove_ascii( list, element );
625 return( list );
629 * fma_core_utils_slist_count:
630 * @list: the GSList of strings to be searched.
631 * @str: the searched string.
633 * Search for a string in a string list.
635 * Returns: the count of @ßtr in @list list.
637 * Since: 2.30
639 guint
640 fma_core_utils_slist_count( GSList *list, const gchar *str )
642 guint count;
643 GSList *il;
645 count = 0;
647 for( il = list ; il ; il = il->next ){
648 const gchar *istr = ( const gchar * ) il->data;
649 if( !fma_core_utils_str_collate( str, istr )){
650 count += 1;
654 return( count );
658 * fma_core_utils_slist_find_negated:
659 * @list: the GSList of strings to be searched.
660 * @str: the searched string.
662 * Search for a string in a string list which may contain nagated items.
664 * Returns: %TRUE if the string has been found in list.
666 * Since: 2.30
668 gboolean
669 fma_core_utils_slist_find_negated( GSList *list, const gchar *str )
671 GSList *il;
673 for( il = list ; il ; il = il->next ){
674 const gchar *istr = g_strstrip( g_strdup( ( const gchar * ) il->data ));
676 if( istr[0] == '!' ){
677 gchar *istrdup = g_strdup( istr+1 );
678 int match = fma_core_utils_str_collate( str, istrdup );
679 g_free( istrdup );
680 if( match == 0 ){
681 return( TRUE );
684 } else if( fma_core_utils_str_collate( str, istr ) == 0 ){
685 return( TRUE );
689 return( FALSE );
693 * fma_core_utils_slist_are_equal:
694 * @a: a GSList of strings.
695 * @b: another GSList of strings to be compared with @first.
697 * Compare two string lists, without regards to the order.
699 * Returns: %TRUE if the two lists have same content.
701 * Since: 2.30
703 gboolean
704 fma_core_utils_slist_are_equal( GSList *a, GSList *b )
706 GSList *il;
708 for( il = a ; il ; il = il->next ){
709 const gchar *str = ( const gchar * ) il->data;
710 if( fma_core_utils_slist_count( b, str ) == 0 ){
711 return( FALSE );
715 for( il = b ; il ; il = il->next ){
716 const gchar *str = ( const gchar * ) il->data;
717 if( fma_core_utils_slist_count( a, str ) == 0 ){
718 return( FALSE );
722 return( TRUE );
726 * fma_core_utils_slist_free:
727 * @slist: a #GSList list of strings.
729 * Releases the strings and the list itself.
731 * Since: 2.30
733 void
734 fma_core_utils_slist_free( GSList *slist )
736 g_slist_foreach( slist, ( GFunc ) g_free, NULL );
737 g_slist_free( slist );
741 * fma_core_utils_gstring_joinv:
742 * @start: a prefix to be written at the beginning of the output string.
743 * @separator: a string to be used as separator.
744 * @list: the list of strings to be concatenated.
746 * Concatenates a gchar **list of strings to a new string.
748 * Returns: a newly allocated string which should be g_free() by the caller.
750 * Since: 2.30
752 gchar *
753 fma_core_utils_gstring_joinv( const gchar *start, const gchar *separator, gchar **list )
755 GString *tmp_string = g_string_new( "" );
756 int i;
758 g_return_val_if_fail( list != NULL, NULL );
760 if( start != NULL ){
761 tmp_string = g_string_append( tmp_string, start );
764 if( list[0] != NULL ){
765 tmp_string = g_string_append( tmp_string, list[0] );
768 for( i = 1 ; list[i] != NULL ; i++ ){
769 if( separator ){
770 tmp_string = g_string_append( tmp_string, separator );
772 tmp_string = g_string_append( tmp_string, list[i] );
775 return( g_string_free( tmp_string, FALSE ));
778 /***
779 * fma_core_utils_selcount_get_ope:
780 * @selcount: the selection count condition string.
781 * @ope: a pointer to a newly allocated string which will contains the
782 * operation code.
783 * @uint: a pointer to a newly allocated string which will contains the
784 * relevant integer.
786 * Parses a selection count string, and extract the operation code and the
787 * relevant integer.
789 * The two returned strings must be g_free() by the caller.
791 * Since: 2.30
793 void
794 fma_core_utils_selcount_get_ope_int( const gchar *selcount, gchar **ope, gchar **uint )
796 gchar *dup, *dup2;
797 guint uint_int;
799 g_return_if_fail( ope && uint );
801 *ope = NULL;
802 *uint = NULL;
804 dup = g_strstrip( g_strdup( selcount ));
805 *ope = g_strdup( " " );
806 *ope[0] = dup[0];
808 dup2 = g_strstrip( g_strdup( dup+1 ));
809 uint_int = abs( atoi( dup2 ));
810 *uint = g_strdup_printf( "%d", uint_int );
812 g_free( dup2 );
813 g_free( dup );
817 * fma_core_utils_dir_is_writable_path:
818 * @path: the path of the directory to be tested.
820 * Returns: %TRUE if the directory is writable, %FALSE else.
822 * Please note that this type of test is subject to race conditions,
823 * as the directory may become unwritable after a successful test,
824 * but before the caller has been able to actually write into it.
826 * There is no "super-test". Just try...
828 * Since: 2.30
830 gboolean
831 fma_core_utils_dir_is_writable_path( const gchar *path )
833 static const gchar *thisfn = "fma_core_utils_path_is_writable";
834 GFile *file;
835 gboolean writable;
837 if( !path || !g_utf8_strlen( path, -1 )){
838 g_warning( "%s: empty path", thisfn );
839 return( FALSE );
842 file = g_file_new_for_path( path );
843 writable = info_dir_is_writable( file, path );
844 g_object_unref( file );
846 return( writable );
850 * fma_core_utils_dir_is_writable_uri:
851 * @uri: the URI of the directory to be tested.
853 * Returns: %TRUE if the directory is writable, %FALSE else.
855 * Please note that this type of test is subject to race conditions,
856 * as the directory may become unwritable after a successful test,
857 * but before the caller has been able to actually write into it.
859 * There is no "super-test". Just try...
861 * Since: 2.30
863 gboolean
864 fma_core_utils_dir_is_writable_uri( const gchar *uri )
866 static const gchar *thisfn = "fma_core_utils_dir_is_writable_uri";
867 GFile *file;
868 gboolean writable;
870 if( !uri || !g_utf8_strlen( uri, -1 )){
871 g_warning( "%s: empty uri", thisfn );
872 return( FALSE );
875 file = g_file_new_for_uri( uri );
876 writable = info_dir_is_writable( file, uri );
877 g_object_unref( file );
879 return( writable );
882 static gboolean
883 info_dir_is_writable( GFile *file, const gchar *path_or_uri )
885 static const gchar *thisfn = "fma_core_utils_info_dir_is_writable";
886 GError *error = NULL;
887 GFileInfo *info;
888 GFileType type;
889 gboolean writable;
891 info = g_file_query_info( file,
892 G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE "," G_FILE_ATTRIBUTE_STANDARD_TYPE,
893 G_FILE_QUERY_INFO_NONE, NULL, &error );
895 if( error ){
896 if( error->code != G_IO_ERROR_NOT_FOUND ){
897 g_warning( "%s: g_file_query_info error: %s", thisfn, error->message );
899 g_error_free( error );
900 return( FALSE );
903 type = g_file_info_get_file_type( info );
904 if( type != G_FILE_TYPE_DIRECTORY ){
905 g_debug( "%s: %s is not a directory", thisfn, path_or_uri );
906 g_object_unref( info );
907 return( FALSE );
910 writable = g_file_info_get_attribute_boolean( info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE );
911 if( !writable ){
912 g_debug( "%s: %s is not writable", thisfn, path_or_uri );
915 g_object_unref( info );
917 return( writable );
921 * fma_core_utils_dir_list_perms:
922 * @path: the path of the directory to be tested.
923 * @message: a message to be printed if not %NULL.
925 * Displays the permissions of the directory on debug output.
927 * Since: 3.1
929 void
930 fma_core_utils_dir_list_perms( const gchar *path, const gchar *message )
932 list_perms( path, message, "ls -ld" );
936 * fma_core_utils_dir_split_ext:
937 * @string: the input path or URI to be splitted.
938 * @first: a pointer to a buffer which will contain the first part of the split.
939 * @ext: a pointer to a buffer which will contain the extension part of the path.
941 * Split the given @string, returning the first part and the extension in newly
942 * allocated buffers which should be g_free() by the caller.
944 * The extension is set to an empty string if no extension is detected.
946 * Since: 2.30
948 void
949 fma_core_utils_dir_split_ext( const gchar *string, gchar **first, gchar **ext )
951 gchar *dupped;
952 gchar **array, **iter;
954 dupped = g_strreverse( g_strdup( string ));
955 array = g_strsplit( dupped, ".", 2 );
957 if( g_strv_length( array ) == 1 ){
958 if( ext ){
959 *ext = g_strdup( "" );
961 if( first ){
962 *first = g_strreverse( g_strdup(( const gchar * ) *array ));
964 } else {
965 if( ext ){
966 *ext = g_strreverse( g_strdup(( const gchar * ) *array ));
968 iter = array;
969 ++iter;
970 if( first ){
971 *first = g_strreverse( g_strdup(( const gchar * ) *iter ));
975 g_strfreev( array );
976 g_free( dupped );
980 * fma_core_utils_file_delete:
981 * @path: the path of the file to be deleted.
983 * Returns: %TRUE if the file is successfully deleted, %FALSE else.
985 * Since: 2.30
987 gboolean
988 fma_core_utils_file_delete( const gchar *path )
990 static const gchar *thisfn = "fma_core_utils_file_delete";
991 gboolean deleted = FALSE;
993 if( !path || !g_utf8_strlen( path, -1 )){
994 return( FALSE );
997 if( g_unlink( path ) == 0 ){
998 deleted = TRUE;
1000 } else {
1001 g_warning( "%s: %s: %s", thisfn, path, g_strerror( errno ));
1004 return( deleted );
1008 * fma_core_utils_file_exists:
1009 * @uri: a file URI.
1011 * Returns: %TRUE if the specified file exists, %FALSE else.
1013 * Race condition: cf. fma_core_utils_dir_is_writable_path() and
1014 * fma_core_utils_dir_is_writable_uri() comments.
1016 * Since: 2.30
1018 gboolean
1019 fma_core_utils_file_exists( const gchar *uri )
1021 GFile *file;
1022 gboolean exists;
1024 file = g_file_new_for_uri( uri );
1025 exists = g_file_query_exists( file, NULL );
1026 g_object_unref( file );
1028 return( exists );
1032 * fma_core_utils_file_is_loadable:
1033 * @uri: the URI to be checked.
1035 * Checks that the file is suitable to be loaded in memory, because
1036 * it is not empty, and its size is reasonable (less than 1MB).
1037 * Also checks that a file is a regular file (or a symlink to a
1038 * regular file).
1040 * Returns: whether the file is suitable to be loaded in memory.
1042 * Since: 3.1
1044 gboolean
1045 fma_core_utils_file_is_loadable( const gchar *uri )
1047 static const gchar *thisfn = "fma_core_utils_file_is_loadable";
1048 GFile *file;
1049 gboolean isok;
1051 g_debug( "%s: uri=%s", thisfn, uri );
1053 isok = FALSE;
1054 file = g_file_new_for_uri( uri );
1056 isok = file_is_loadable( file );
1058 g_object_unref( file );
1060 return( isok );
1063 static gboolean
1064 file_is_loadable( GFile *file )
1066 static const gchar *thisfn = "fma_core_utils_file_is_loadable";
1067 GError *error;
1068 GFileInfo *info;
1069 guint64 size;
1070 GFileType type;
1071 gboolean isok;
1072 GFile *target_file;
1074 error = NULL;
1075 isok = FALSE;
1076 info = g_file_query_info( file,
1077 G_FILE_ATTRIBUTE_STANDARD_SIZE "," G_FILE_ATTRIBUTE_STANDARD_TYPE,
1078 G_FILE_QUERY_INFO_NONE, NULL, &error );
1080 if( !info ){
1081 if( error ){
1082 g_debug( "%s: %s", thisfn, error->message );
1083 g_error_free( error );
1086 } else {
1087 size = g_file_info_get_attribute_uint64( info, G_FILE_ATTRIBUTE_STANDARD_SIZE );
1088 g_debug( "%s: size=%lu", thisfn, ( unsigned long ) size );
1089 isok = ( size >= SIZE_MIN && size <= SIZE_MAX );
1092 if( isok ){
1093 type = g_file_info_get_file_type( info );
1094 g_debug( "%s: type=%u", thisfn, ( unsigned ) type );
1096 if( type != G_FILE_TYPE_REGULAR ){
1097 isok = FALSE;
1099 if( type == G_FILE_TYPE_SYMBOLIC_LINK ){
1100 const char *target = g_file_info_get_symlink_target( info );
1101 if( target && strlen( target )){
1102 target_file = g_file_resolve_relative_path( file, target );
1103 if( target_file ){
1104 isok = file_is_loadable( target_file );
1105 g_object_unref( target_file );
1112 g_object_unref( info );
1114 return( isok );
1118 * fma_core_utils_file_list_perms:
1119 * @path: the path of the file to be tested.
1120 * @message: a message to be printed if not %NULL.
1122 * Displays the permissions of the file on debug output.
1124 * Since: 3.2
1126 void
1127 fma_core_utils_file_list_perms( const gchar *path, const gchar *message )
1129 list_perms( path, message, "ls -l" );
1132 static void
1133 list_perms( const gchar *path, const gchar *message, const gchar *command )
1135 static const gchar *thisfn = "fma_core_utils_list_perms";
1136 gchar *cmd;
1137 gchar *out, *err;
1138 GError *error;
1140 error = NULL;
1141 cmd = g_strdup_printf( "%s %s", command, path );
1143 if( !g_spawn_command_line_sync( cmd, &out, &err, NULL, &error )){
1144 g_warning( "%s: %s", thisfn, error->message );
1145 g_error_free( error );
1147 } else {
1148 g_debug( "%s: out=%s", message, out );
1149 g_debug( "%s: err=%s", message, err );
1150 g_free( out );
1151 g_free( err );
1154 g_free( cmd );
1158 * fma_core_utils_file_load_from_uri:
1159 * @uri: the URI the file must be loaded from.
1160 * @length: a pointer to the length of the read content.
1162 * Loads the file into a newly allocated buffer, and set up the length of the
1163 * read content if not %NULL.
1165 * Returns: the newly allocated buffer which contains the file content, or %NULL.
1166 * This buffer should be g_free() by the caller.
1168 * Since: 2.30
1170 gchar *
1171 fma_core_utils_file_load_from_uri( const gchar *uri, gsize *length )
1173 static const gchar *thisfn = "fma_core_utils_file_load_from_uri";
1174 gchar *data;
1175 GFile *file;
1176 GError *error;
1178 g_debug( "%s: uri=%s, length=%p", thisfn, uri, ( void * ) length );
1180 error = NULL;
1181 data = NULL;
1182 if( length ){
1183 *length = 0;
1186 file = g_file_new_for_uri( uri );
1188 if( !g_file_load_contents( file, NULL, &data, length, NULL, &error )){
1189 g_free( data );
1190 data = NULL;
1191 if( length ){
1192 *length = 0;
1194 if( error ){
1195 g_debug( "%s: %s", thisfn, error->message );
1196 g_error_free( error );
1200 g_object_unref( file );
1202 return( data );
1206 * fma_core_utils_print_version:
1208 * Print a version message on the console
1210 * <programlisting>
1211 * filemanager-actions-new (FileManager-Actions) v 2.29.1
1212 * Copyright (C) 2005-2007 Frederic Ruaudel
1213 * Copyright (C) 2009, 2010, 2011, 2012 Pierre Wieser
1214 * FileManager-Actions is free software, licensed under GPLv2 or later.
1215 * </programlisting>
1217 * Since: 2.30
1219 void
1220 fma_core_utils_print_version( void )
1222 gchar *copyright;
1224 g_print( "\n" );
1225 g_print( "%s (%s) v %s\n", g_get_prgname(), PACKAGE_NAME, PACKAGE_VERSION );
1226 copyright = fma_about_get_copyright( TRUE );
1227 g_print( "%s\n", copyright );
1228 g_free( copyright );
1230 g_print( "%s is free software, and is provided without any warranty. You may\n", PACKAGE_NAME );
1231 g_print( "redistribute copies of %s under the terms of the GNU General Public\n", PACKAGE_NAME );
1232 g_print( "License (see COPYING).\n" );
1233 g_print( "\n" );
1235 g_debug( "Program has been compiled against Glib %d.%d.%d, Gtk+ %d.%d.%d",
1236 GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION,
1237 GTK_MAJOR_VERSION, GTK_MINOR_VERSION, GTK_MICRO_VERSION );
1239 g_debug( "Current system runs Glib %d.%d.%d, Gtk+ %d.%d.%d\n",
1240 glib_major_version, glib_minor_version, glib_micro_version,
1241 gtk_major_version, gtk_minor_version, gtk_micro_version );