2 * irreco - Ir Remote Control
3 * Copyright (C) 2007 Arto Karppinen (arto.karppinen@iki.fi),
4 * Harri Vattulainen (t5vaha01@students.oamk.fi)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (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 Foundation,
18 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23 #include "irreco_util.h"
24 #include <sys/socket.h>
28 * @addtogroup IrrecoMisc
31 * All kinds of usefull stuff that isnt really part of Irreco. Does not
32 * pull any other Irreco headers, so it can be safely included inside backends.
39 * Source file of @ref IrrecoMisc.
44 * All kinds of usefull stuff that isnt really part of Irreco. Does not pull
45 * any other Irreco headers, so it can be safely included inside backends.
48 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
49 /* Public Functions */
50 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
54 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
55 /* Files and directories. */
56 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
59 * @name Files and directories
64 * Check if the given filename is a directory.
66 int irreco_is_dir(const char *filename
)
70 char *realpath
= canonicalize_file_name(filename
);
71 rval
= (realpath
!= NULL
) &&
72 (stat(filename
, &buf
) == 0) &&
79 * Check if a given file is a regular file.
81 int irreco_is_file(const char *filename
)
85 char *realpath
= canonicalize_file_name(filename
);
86 rval
= (realpath
!= NULL
) &&
87 (stat(filename
, &buf
) == 0) &&
94 * Does the the file or dir exists.
96 int irreco_file_exists(const char *filename
)
98 struct stat struct_stat
;
99 if (stat(filename
, &struct_stat
) == 0) {
106 * Return length of file
107 * Return 0 if file doesn't exist
109 gint
irreco_file_length(const gchar
*filename
)
111 struct stat struct_stat
;
113 if(!irreco_file_exists(filename
)) {
117 stat(filename
, &struct_stat
);
118 return struct_stat
.st_size
;
122 * Write data to file.
124 gboolean
irreco_write_file(const gchar
* file
, const gchar
* data
,
131 if ((handle
= fopen(file
, "w")) == NULL
) {
132 IRRECO_ERROR("Failed to open \"%s\" for writing.\n", file
);
133 IRRECO_RETURN_BOOL(FALSE
);
136 written
= fwrite(data
, sizeof(gchar
), data_size
, handle
);
139 if (written
!= data_size
) {
140 IRRECO_ERROR("Failed to write data to \"%s\". "
141 "Data size \"%u\", wrote \"%u\".\n",
142 file
, data_size
, written
);
143 IRRECO_RETURN_BOOL(FALSE
);
145 IRRECO_RETURN_BOOL(TRUE
);
149 * Read contents of file into a buffer, or at least as much of the file the
150 * buffer can contain.
152 gboolean
irreco_read_text_file(const gchar
* file
, gchar
*buffer
,
159 if ((fd
= fopen(file
, "r")) == NULL
) return FALSE
;
160 count
= fread(buffer
, 1, buffer_size
, fd
);
161 buffer
[count
] = '\0';
162 if (count
< 1) return FALSE
;
167 * Read contents of binary file into a buffer, or at least as much of the file the
168 * buffer can contain.
170 gboolean
irreco_read_binary_file(const gchar
*file
, guchar
*buffer
,
171 gsize buffer_size
, gint
*binlen
)
176 if ((fd
= g_fopen(file
, "rb")) == NULL
) return FALSE
;
177 count
= (gint
) fread(buffer
, 1, buffer_size
, fd
);
179 if (count
< 1) return FALSE
;
185 * Read a line of text from file to buffer.
187 gboolean
irreco_read_line(const gchar
* file
, gchar
*buffer
,
192 if (!irreco_read_text_file(file
, buffer
, buffer_size
)) return FALSE
;
193 for (i
= 0; i
< buffer_size
; i
++) {
194 if (buffer
[i
] == '\0' || buffer
[i
] == '\n') {
203 * Write GKeyFile contents to file.
205 gboolean
irreco_write_keyfile(GKeyFile
* keyfile
, const gchar
* file
)
209 GError
*error
= NULL
;
213 data
= g_key_file_to_data(keyfile
, &data_size
, &error
);
214 if (irreco_gerror_check_print(&error
)) {
215 IRRECO_RETURN_BOOL(FALSE
);
218 success
= irreco_write_file(file
, data
, data_size
);
220 IRRECO_RETURN_BOOL(success
);
224 * Read all filenames that match suffix from directory.
226 gboolean
irreco_dir_foreach(IrrecoDirForeachData
*dir_data
,
227 IrrecoDirForeachCallback callback
)
229 GError
*error
= NULL
;
234 dir
= g_dir_open(dir_data
->directory
, 0, &error
);
235 if (irreco_gerror_check_print(&error
)) {
236 IRRECO_ERROR("Could not read directory: \"%s\"\n",
237 dir_data
->directory
);
239 IRRECO_RETURN_BOOL(FALSE
);
243 while ((dir_data
->filename
= g_dir_read_name(dir
)) != NULL
) {
244 if (g_str_has_suffix(dir_data
->filename
,
245 dir_data
->filesuffix
)) {
246 dir_data
->filepath
= g_build_path("/",
247 dir_data
->directory
, dir_data
->filename
, NULL
);
249 g_free((void*)dir_data
->filepath
);
253 IRRECO_RETURN_BOOL(TRUE
);
259 * Read all filenames that match suffix.
260 * Searches ONLY thru subdirectories.
262 gboolean
irreco_dir_foreach_subdirectories(IrrecoDirForeachData
*dir_data
,
263 IrrecoDirForeachCallback callback
)
265 GError
*error
= NULL
;
268 gchar
*subpath
= NULL
;
269 const gchar
*buttonsdir
;
270 const gchar
*directorykeeper
= dir_data
->directory
;
274 dir
= g_dir_open(dir_data
->directory
, 0, &error
);
275 if (irreco_gerror_check_print(&error
)) {
276 IRRECO_ERROR("Could not read directory: \"%s\"\n",
277 dir_data
->directory
);
278 IRRECO_RETURN_BOOL(FALSE
);
281 /* Read buttons dir file by file (also directories) */
282 while ((buttonsdir
= g_dir_read_name(dir
)) != NULL
) {
284 /* Create possible subpath from readed files */
285 subpath
= g_build_path("/", dir_data
->directory
,
288 /* Test if subpath is folder */
289 if(g_file_test(subpath
, G_FILE_TEST_IS_DIR
)) {
291 /* Create GDir from directory or multifail instantly */
292 subdir
= g_dir_open(subpath
, 0, &error
);
293 if (irreco_gerror_check_print(&error
)) {
294 IRRECO_ERROR("Could not read dir: \"%s\"\n",
298 IRRECO_RETURN_BOOL(FALSE
);
301 /* Start reading files from subdirectory */
302 while ((dir_data
->filename
= g_dir_read_name(subdir
))
305 /* Find files with wanted suffix */
306 if (g_str_has_suffix(dir_data
->filename
,
307 dir_data
->filesuffix
)) {
309 dir_data
->filepath
= g_build_path("/",
313 dir_data
->directory
= subpath
;
315 dir_data
->directory
= directorykeeper
;
316 g_free((void*)dir_data
->filepath
);
325 if(dir
!= NULL
) g_dir_close(dir
);
326 if(subdir
!= NULL
) g_dir_close(subdir
);
327 if(subpath
!= NULL
) g_free(subpath
);
328 IRRECO_RETURN_BOOL(TRUE
);
332 * Create path to directory $HOME/.APP_NAME, and attempt to create the
333 * directory if it does not exists.
335 * @return Directory path inside a newly allocated string,
336 * or NULL if the directory could not be created.
338 gchar
* irreco_get_config_dir(const gchar
* app_name
)
340 GString
*app_name_with_dot
;
345 if ((home
= getenv("HOME")) == NULL
) IRRECO_RETURN_PTR(NULL
);
347 app_name_with_dot
= g_string_new(".");
348 g_string_append(app_name_with_dot
, app_name
);
349 apphome
= g_build_path("/", home
, app_name_with_dot
->str
, NULL
);
350 g_string_free(app_name_with_dot
, TRUE
);
352 if (irreco_is_dir(apphome
) == TRUE
353 || g_mkdir(apphome
, 0700) == 0)
354 IRRECO_RETURN_PTR(apphome
);
357 IRRECO_RETURN_PTR(NULL
);
361 * Get path to $HOME/.APP_NAME/FILE
363 * @return Newly allocated string which contains path to config file or NULL.
365 gchar
* irreco_get_config_file(const gchar
* app_name
, const gchar
* file
)
371 if ((config_dir
= irreco_get_config_dir(app_name
)) != NULL
) {
372 config_file
= g_build_path("/", config_dir
, file
, NULL
);
374 IRRECO_RETURN_PTR(config_file
);
376 IRRECO_RETURN_PTR(NULL
);
383 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
385 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
393 * Replace characters.
395 void irreco_char_replace(gchar
* string
, gchar what
, gchar with
)
399 for (i
= 0; string
[i
] != '\0'; i
++) {
400 if (string
[i
] == what
) {
408 * Find first occurrence of character inside string.
410 * @return Position of character or -1.
412 gint
irreco_char_pos(const gchar
* string
, gchar what
)
417 for (i
= 0; string
[i
] != '\0'; i
++) {
418 if (string
[i
] == what
) {
419 IRRECO_RETURN_INT(i
);
422 IRRECO_RETURN_INT(-1);
426 * Check if the string is empty.
428 * String is empty if it is:
431 * @li Full of space characters.
433 gboolean
irreco_str_isempty(const gchar
* string
)
437 if (string
== NULL
|| string
[0] == '\0') IRRECO_RETURN_BOOL(TRUE
);
439 if (g_unichar_isspace(g_utf8_get_char(string
)) == FALSE
) {
440 IRRECO_RETURN_BOOL(FALSE
);
442 printf("\"%s\" %p\n", string
, string
);
443 } while ((string
= g_utf8_find_next_char(string
, NULL
)) != NULL
444 && string
[0] != '\0');
446 IRRECO_RETURN_BOOL(TRUE
);
450 * Copy C-string into GString.
452 void irreco_gstring_set(GString
* g_str
, const gchar
* c_str
)
457 g_string_assign(g_str
, "");
459 g_string_assign(g_str
, c_str
);
466 * Copy C-string into GString and free C-string.
468 void irreco_gstring_set_and_free(GString
* g_str
, gchar
* c_str
)
473 g_string_assign(g_str
, "");
475 g_string_assign(g_str
, c_str
);
485 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
486 /* Error handling. */
487 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
490 * @name Error handling
496 * If GError is set, print message, release GError, and return TRUE.
497 * Otherwise returns FALSE.
499 gboolean
irreco_gerror_check_print(GError
** error
)
501 if (*error
!= NULL
) {
502 IRRECO_PRINTF("GError: %s\n", (*error
)->message
);
503 g_error_free(*error
);
511 * If GError is set, free it, and return TRUE.
512 * Otherwise returns FALSE.
514 gboolean
irreco_gerror_check_free(GError
** error
)
516 if (*error
!= NULL
) {
517 g_error_free(*error
);
526 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
528 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
538 void irreco_info_dlg(GtkWindow
* parent_window
, const gchar
* message
)
543 dialog
= gtk_message_dialog_new(parent_window
,
544 GTK_DIALOG_DESTROY_WITH_PARENT
,
545 GTK_MESSAGE_INFO
, GTK_BUTTONS_OK
, "%s", message
);
546 gtk_dialog_run(GTK_DIALOG(dialog
));
547 gtk_widget_destroy(dialog
);
555 void irreco_error_dlg(GtkWindow
* parent_window
, const gchar
* message
)
560 dialog
= gtk_message_dialog_new(parent_window
,
561 GTK_DIALOG_DESTROY_WITH_PARENT
,
562 GTK_MESSAGE_ERROR
, GTK_BUTTONS_OK
, "%s", message
);
563 gtk_dialog_run(GTK_DIALOG(dialog
));
564 gtk_widget_destroy(dialog
);
570 * Format message, and show error popup.
572 void irreco_info_dlg_printf(GtkWindow
* parent_window
,
573 const gchar
* format
, ...)
577 gchar
*message
= NULL
;
580 va_start(args
, format
);
581 rvalue
= g_vasprintf(&message
, format
, args
);
585 irreco_info_dlg(parent_window
, message
);
588 IRRECO_ERROR("Could not format message.\n");
595 * Format message, and show error popup.
597 void irreco_error_dlg_printf(GtkWindow
* parent_window
,
598 const gchar
* format
, ...)
602 gchar
*message
= NULL
;
605 va_start(args
, format
);
606 rvalue
= g_vasprintf(&message
, format
, args
);
610 irreco_error_dlg(parent_window
, message
);
613 IRRECO_ERROR("Could not format message.\n");
620 * Popup yes / no dialog.
622 * Returns: TRUE if user click YES, FALSE otherwise.
624 gboolean
irreco_yes_no_dlg(GtkWindow
* parent_window
, const gchar
* message
)
630 dialog
= gtk_message_dialog_new(parent_window
,
631 GTK_DIALOG_DESTROY_WITH_PARENT
, GTK_MESSAGE_QUESTION
,
632 GTK_BUTTONS_YES_NO
, "%s", message
);
633 responce
= gtk_dialog_run(GTK_DIALOG(dialog
));
634 gtk_widget_destroy(dialog
);
635 IRRECO_RETURN_BOOL(responce
== GTK_RESPONSE_YES
);
639 * Convenience frapper of gtk_alignment_new().
641 GtkWidget
*irreco_gtk_align(GtkWidget
*child
,
647 guint padding_bottom
,
654 align
= gtk_alignment_new(xalign
, yalign
, xscale
, yscale
);
655 gtk_alignment_set_padding(GTK_ALIGNMENT(align
), padding_top
,
656 padding_bottom
, padding_left
, padding_right
);
657 gtk_container_add(GTK_CONTAINER(align
), child
);
658 IRRECO_RETURN_PTR(align
);
662 * Create, align, and pad label.
664 GtkWidget
*irreco_gtk_label(const gchar
* str
,
668 guint padding_bottom
,
675 label
= gtk_label_new(str
);
676 gtk_misc_set_alignment(GTK_MISC(label
), xalign
, yalign
);
677 IRRECO_RETURN_PTR(irreco_gtk_pad(label
, padding_top
, padding_bottom
,
678 padding_left
, padding_right
));
682 * Create, align, and pad a label with bold text.
684 GtkWidget
*irreco_gtk_label_bold(const gchar
* str
,
688 guint padding_bottom
,
696 label
= irreco_gtk_label(NULL
, xalign
, yalign
, padding_top
,
697 padding_bottom
, padding_left
, padding_right
);
698 markup
= g_markup_printf_escaped("<b>%s</b>", str
);
699 gtk_label_set_markup(GTK_LABEL(gtk_bin_get_child(GTK_BIN(label
))),
702 IRRECO_RETURN_PTR(label
);
706 * Get button widget for dialog buttons.
708 * @param dialog GtkDialog
709 * @param n Index of button to get.
711 GtkWidget
*irreco_gtk_dialog_get_button(GtkWidget
*dialog
, guint n
)
715 GtkBoxChild
*box_child
;
719 action_area
= GTK_BOX(GTK_DIALOG(dialog
)->action_area
);
720 length
= g_list_length(action_area
->children
);
723 IRRECO_ERROR("Cant get button \"%i\". "
724 "Dialog has only \"%i\" buttons", n
, length
);
725 IRRECO_RETURN_PTR(NULL
);
728 box_child
= (GtkBoxChild
*) g_list_nth_data(g_list_first(
729 action_area
->children
), n
);
730 IRRECO_RETURN_PTR(box_child
->widget
);
733 GtkWindow
*irreco_gtk_get_parent_window(GtkWidget
*widget
)
738 parent
= gtk_widget_get_toplevel(widget
);
739 if (GTK_WIDGET_TOPLEVEL(parent
) != TRUE
740 || GTK_IS_WINDOW(parent
) != TRUE
) {
741 IRRECO_RETURN_PTR(GTK_WINDOW(parent
));
743 IRRECO_RETURN_PTR(NULL
);
747 * This function is a modified version of gtk_dialog_new_empty() from GTK
748 * sources, which is used to by gtk_dialog_new_with_buttons() to set the
749 * settings of a dialog.
751 void irreco_gtk_dialog_set(GtkDialog
*dialog
,
754 GtkDialogFlags flags
)
759 gtk_window_set_title(GTK_WINDOW (dialog
), title
);
762 gtk_window_set_transient_for(GTK_WINDOW (dialog
), parent
);
764 if (flags
& GTK_DIALOG_MODAL
)
765 gtk_window_set_modal(GTK_WINDOW (dialog
), TRUE
);
767 if (flags
& GTK_DIALOG_DESTROY_WITH_PARENT
)
768 gtk_window_set_destroy_with_parent(GTK_WINDOW (dialog
), TRUE
);
770 if (flags
& GTK_DIALOG_NO_SEPARATOR
)
771 gtk_dialog_set_has_separator(dialog
, FALSE
);
778 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
780 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
789 * Do not use, use GTimer instead.
793 * Difference of time in microseconds between two GTimeVals.
794 * This works fine as long as the difference is no more than 2146 seconds.
796 glong
irreco_time_diff(GTimeVal
*start
, GTimeVal
*end
)
801 diff
.tv_sec
= end
->tv_sec
- start
->tv_sec
;
802 diff
.tv_usec
= end
->tv_usec
- start
->tv_usec
;
804 /* We run out of space in ulong after 2147 seconds. */
805 if (diff
.tv_sec
>= G_MAXLONG
/ IRRECO_SECOND_IN_USEC
) {
806 IRRECO_RETURN_LONG((G_MAXLONG
/ IRRECO_SECOND_IN_USEC
)
807 * IRRECO_SECOND_IN_USEC
);
810 IRRECO_RETURN_LONG(diff
.tv_sec
* IRRECO_SECOND_IN_USEC
+ diff
.tv_usec
);
815 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
817 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
825 * Check if the socket is valid.
827 gboolean
irreco_is_socket_valid(int socket
)
834 /* This should succeed if socket is valid. */
835 rvalue
= getsockopt(socket
, SOL_SOCKET
, SOCK_STREAM
, &optval
, &optlen
);
838 IRRECO_RETURN_BOOL(TRUE
);
841 /* glibc docs say these are the possible error values. */
843 case EBADF
: IRRECO_PRINTF("Error: EBADF\n"); break;
844 case ENOTSOCK
: IRRECO_PRINTF("Error: ENOTSOCK\n"); break;
845 case ENOPROTOOPT
: IRRECO_PRINTF("Error: ENOPROTOOPT\n"); break;
846 default: IRRECO_PRINTF("Error: Unknown\n"); break;
849 IRRECO_RETURN_BOOL(FALSE
);