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>
32 * All kinds of usefull stuff that isnt really part of Irreco. Does not pull
33 * any other Irreco headers, so it can be safely included inside backends.
38 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
39 /* Files and directories. */
40 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
43 * Check if the given filename is a directory.
45 int irreco_is_dir(const char *filename
)
49 char *realpath
= canonicalize_file_name(filename
);
50 rval
= (realpath
!= NULL
) &&
51 (stat(filename
, &buf
) == 0) &&
58 * Check if a given file is a regular file.
60 int irreco_is_file(const char *filename
)
64 char *realpath
= canonicalize_file_name(filename
);
65 rval
= (realpath
!= NULL
) &&
66 (stat(filename
, &buf
) == 0) &&
73 * Does the the file or dir exists.
75 int irreco_file_exists(const char *filename
)
77 struct stat struct_stat
;
78 if (stat(filename
, &struct_stat
) == 0) {
87 gboolean
irreco_write_file(const gchar
* file
, const gchar
* data
,
94 if ((handle
= fopen(file
, "w")) == NULL
) {
95 IRRECO_ERROR("Failed to open \"%s\" for writing.\n", file
);
96 IRRECO_RETURN_BOOL(FALSE
);
99 written
= fwrite(data
, sizeof(gchar
), data_size
, handle
);
102 if (written
!= data_size
) {
103 IRRECO_ERROR("Failed to write data to \"%s\". "
104 "Data size \"%u\", wrote \"%u\".\n",
105 file
, data_size
, written
);
106 IRRECO_RETURN_BOOL(FALSE
);
108 IRRECO_RETURN_BOOL(TRUE
);
112 * Read contents of file into a buffer, or at least as much of the file the
113 * buffer can contain.
115 gboolean
irreco_read_text_file(const gchar
* file
, gchar
*buffer
,
122 if ((fd
= fopen(file
, "r")) == NULL
) return FALSE
;
123 count
= fread(buffer
, 1, buffer_size
, fd
);
124 buffer
[count
] = '\0';
125 if (count
< 1) return FALSE
;
130 * Read a line of text from file to buffer.
132 gboolean
irreco_read_line(const gchar
* file
, gchar
*buffer
,
137 if (!irreco_read_text_file(file
, buffer
, buffer_size
)) return FALSE
;
138 for (i
= 0; i
< buffer_size
; i
++) {
139 if (buffer
[i
] == '\0' || buffer
[i
] == '\n') {
148 * Write GKeyFile contents to file.
150 gboolean
irreco_write_keyfile(GKeyFile
* keyfile
, const gchar
* file
)
154 GError
*error
= NULL
;
158 data
= g_key_file_to_data(keyfile
, &data_size
, &error
);
159 if (irreco_gerror_check_print(&error
)) {
160 IRRECO_RETURN_BOOL(FALSE
);
163 success
= irreco_write_file(file
, data
, data_size
);
165 IRRECO_RETURN_BOOL(success
);
169 * Read all filenames that match suffix from directory.
171 gboolean
irreco_dir_foreach(IrrecoDirForeachData
*dir_data
,
172 IrrecoDirForeachCallback callback
)
174 GError
*error
= NULL
;
179 dir
= g_dir_open(dir_data
->directory
, 0, &error
);
180 if (irreco_gerror_check_print(&error
)) {
181 IRRECO_ERROR("Could not read directory: \"%s\"\n",
182 dir_data
->directory
);
184 IRRECO_RETURN_BOOL(FALSE
);
188 while ((dir_data
->filename
= g_dir_read_name(dir
)) != NULL
) {
189 if (g_str_has_suffix(dir_data
->filename
,
190 dir_data
->filesuffix
)) {
191 dir_data
->filepath
= g_build_path("/",
192 dir_data
->directory
, dir_data
->filename
, NULL
);
194 g_free((void*)dir_data
->filepath
);
198 IRRECO_RETURN_BOOL(TRUE
);
204 * Read all filenames that match suffix.
205 * Searches ONLY thru subdirectories.
207 gboolean
irreco_dir_foreach_subdirectories(IrrecoDirForeachData
*dir_data
,
208 IrrecoDirForeachCallback callback
)
210 GError
*error
= NULL
;
213 const gchar
*subpath
= NULL
;
214 const gchar
*buttonsdir
;
215 const gchar
*directorykeeper
= dir_data
->directory
;
219 dir
= g_dir_open(dir_data
->directory
, 0, &error
);
220 if (irreco_gerror_check_print(&error
)) {
221 IRRECO_ERROR("Could not read directory: \"%s\"\n",
222 dir_data
->directory
);
223 g_dir_close(dir
); IRRECO_RETURN_BOOL(FALSE
);}
225 /* Read buttons dir file by file (also directories) */
226 while ((buttonsdir
= g_dir_read_name(dir
)) != NULL
) {
228 /* Create possible subpath from readed files */
229 subpath
= g_build_path("/", dir_data
->directory
,
232 /* Test if subpath is folder */
233 if(g_file_test(subpath
, G_FILE_TEST_IS_DIR
)) {
235 /* Create GDir from directory or multifail instantly */
236 subdir
= g_dir_open(subpath
, 0, &error
);
237 if (irreco_gerror_check_print(&error
)) {
238 IRRECO_ERROR("Could not read dir: \"%s\"\n", subpath
);
239 g_dir_close(subdir
); IRRECO_RETURN_BOOL(FALSE
);}
241 /* Start reading files from subdirectory */
242 while ((dir_data
->filename
= g_dir_read_name(subdir
))
245 /* Find files with wanted suffix */
246 if (g_str_has_suffix(dir_data
->filename
,
247 dir_data
->filesuffix
)) {
249 dir_data
->filepath
= g_build_path("/",
253 dir_data
->directory
= subpath
;
255 dir_data
->directory
= directorykeeper
;
256 g_free((void*)dir_data
->filepath
);
260 g_free((void*)subpath
);
264 IRRECO_RETURN_BOOL(TRUE
);
268 * Create path to directory $HOME/.APP_NAME, and attempt to create the
269 * directory if it does not exists.
271 * @return Directory path inside a newly allocated string,
272 * or NULL if the directory could not be created.
274 gchar
* irreco_get_config_dir(const gchar
* app_name
)
276 GString
*app_name_with_dot
;
281 if ((home
= getenv("HOME")) == NULL
) IRRECO_RETURN_PTR(NULL
);
283 app_name_with_dot
= g_string_new(".");
284 g_string_append(app_name_with_dot
, app_name
);
285 apphome
= g_build_path("/", home
, app_name_with_dot
->str
, NULL
);
286 g_string_free(app_name_with_dot
, TRUE
);
288 if (irreco_is_dir(apphome
) == TRUE
289 || g_mkdir(apphome
, 0700) == 0)
290 IRRECO_RETURN_PTR(apphome
);
293 IRRECO_RETURN_PTR(NULL
);
297 * Get path to $HOME/.APP_NAME/FILE
299 * @return Newly allocated string which contains path to config file or NULL.
301 gchar
* irreco_get_config_file(const gchar
* app_name
, const gchar
* file
)
307 if ((config_dir
= irreco_get_config_dir(app_name
)) != NULL
) {
308 config_file
= g_build_path("/", config_dir
, file
, NULL
);
310 IRRECO_RETURN_PTR(config_file
);
312 IRRECO_RETURN_PTR(NULL
);
317 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
319 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
322 * Replace characters.
324 void irreco_char_replace(gchar
* string
, gchar what
, gchar with
)
328 for (i
= 0; string
[i
] != '\0'; i
++) {
329 if (string
[i
] == what
) {
337 * Find first occurrence of character inside string.
339 * @return Position of character or -1.
341 gint
irreco_char_pos(const gchar
* string
, gchar what
)
346 for (i
= 0; string
[i
] != '\0'; i
++) {
347 if (string
[i
] == what
) {
348 IRRECO_RETURN_INT(i
);
351 IRRECO_RETURN_INT(-1);
355 * Check if the string is empty.
357 * String is empty if it is:
360 * @li Full of space characters.
362 gboolean
irreco_str_isempty(const gchar
* string
)
366 if (string
== NULL
|| string
[0] == '\0') IRRECO_RETURN_BOOL(TRUE
);
368 if (g_unichar_isspace(g_utf8_get_char(string
)) == FALSE
) {
369 IRRECO_RETURN_BOOL(FALSE
);
371 printf("\"%s\" %p\n", string
, string
);
372 } while ((string
= g_utf8_find_next_char(string
, NULL
)) != NULL
373 && string
[0] != '\0');
375 IRRECO_RETURN_BOOL(TRUE
);
379 * Copy C-string into GString.
381 void irreco_gstring_set(GString
* g_str
, const gchar
* c_str
)
386 g_string_assign(g_str
, "");
388 g_string_assign(g_str
, c_str
);
395 * Copy C-string into GString and free C-string.
397 void irreco_gstring_set_and_free(GString
* g_str
, gchar
* c_str
)
402 g_string_assign(g_str
, "");
404 g_string_assign(g_str
, c_str
);
413 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
414 /* Error handling. */
415 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
418 * If GError is set, print message, release GError, and return TRUE.
419 * Otherwise returns FALSE.
421 gboolean
irreco_gerror_check_print(GError
** error
)
423 if (*error
!= NULL
) {
424 IRRECO_PRINTF("GError: %s\n", (*error
)->message
);
425 g_error_free(*error
);
433 * If GError is set, free it, and return TRUE.
434 * Otherwise returns FALSE.
436 gboolean
irreco_gerror_check_free(GError
** error
)
438 if (*error
!= NULL
) {
439 g_error_free(*error
);
448 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
450 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
455 void irreco_info_dlg(GtkWindow
* parent_window
, const gchar
* message
)
460 dialog
= gtk_message_dialog_new(parent_window
,
461 GTK_DIALOG_DESTROY_WITH_PARENT
,
462 GTK_MESSAGE_INFO
, GTK_BUTTONS_OK
, "%s", message
);
463 gtk_dialog_run(GTK_DIALOG(dialog
));
464 gtk_widget_destroy(dialog
);
472 void irreco_error_dlg(GtkWindow
* parent_window
, const gchar
* message
)
477 dialog
= gtk_message_dialog_new(parent_window
,
478 GTK_DIALOG_DESTROY_WITH_PARENT
,
479 GTK_MESSAGE_ERROR
, GTK_BUTTONS_OK
, "%s", message
);
480 gtk_dialog_run(GTK_DIALOG(dialog
));
481 gtk_widget_destroy(dialog
);
487 * Format message, and show error popup.
489 void irreco_info_dlg_printf(GtkWindow
* parent_window
,
490 const gchar
* format
, ...)
494 gchar
*message
= NULL
;
497 va_start(args
, format
);
498 rvalue
= g_vasprintf(&message
, format
, args
);
502 irreco_info_dlg(parent_window
, message
);
505 IRRECO_ERROR("Could not format message.\n");
512 * Format message, and show error popup.
514 void irreco_error_dlg_printf(GtkWindow
* parent_window
,
515 const gchar
* format
, ...)
519 gchar
*message
= NULL
;
522 va_start(args
, format
);
523 rvalue
= g_vasprintf(&message
, format
, args
);
527 irreco_error_dlg(parent_window
, message
);
530 IRRECO_ERROR("Could not format message.\n");
537 * Popup yes / no dialog.
539 * Returns: TRUE if user click YES, FALSE otherwise.
541 gboolean
irreco_yes_no_dlg(GtkWindow
* parent_window
, const gchar
* message
)
547 dialog
= gtk_message_dialog_new(parent_window
,
548 GTK_DIALOG_DESTROY_WITH_PARENT
, GTK_MESSAGE_QUESTION
,
549 GTK_BUTTONS_YES_NO
, "%s", message
);
550 responce
= gtk_dialog_run(GTK_DIALOG(dialog
));
551 gtk_widget_destroy(dialog
);
552 IRRECO_RETURN_BOOL(responce
== GTK_RESPONSE_YES
);
556 * Convenience frapper of gtk_alignment_new().
558 GtkWidget
*irreco_gtk_align(GtkWidget
*child
,
564 guint padding_bottom
,
571 align
= gtk_alignment_new(xalign
, yalign
, xscale
, yscale
);
572 gtk_alignment_set_padding(GTK_ALIGNMENT(align
), padding_top
,
573 padding_bottom
, padding_left
, padding_right
);
574 gtk_container_add(GTK_CONTAINER(align
), child
);
575 IRRECO_RETURN_PTR(align
);
579 * Create, align, and pad label.
581 GtkWidget
*irreco_gtk_label(const gchar
* str
,
585 guint padding_bottom
,
592 label
= gtk_label_new(str
);
593 gtk_misc_set_alignment(GTK_MISC(label
), xalign
, yalign
);
594 IRRECO_RETURN_PTR(irreco_gtk_pad(label
, padding_top
, padding_bottom
,
595 padding_left
, padding_right
));
599 * Create, align, and pad a label with bold text.
601 GtkWidget
*irreco_gtk_label_bold(const gchar
* str
,
605 guint padding_bottom
,
613 label
= irreco_gtk_label(NULL
, xalign
, yalign
, padding_top
,
614 padding_bottom
, padding_left
, padding_right
);
615 markup
= g_markup_printf_escaped("<b>%s</b>", str
);
616 gtk_label_set_markup(GTK_LABEL(gtk_bin_get_child(GTK_BIN(label
))),
619 IRRECO_RETURN_PTR(label
);
623 * Get button widget for dialog buttons.
625 * @param dialog GtkDialog
626 * @param n Index of button to get.
628 GtkWidget
*irreco_gtk_dialog_get_button(GtkWidget
*dialog
, guint n
)
632 GtkBoxChild
*box_child
;
636 action_area
= GTK_BOX(GTK_DIALOG(dialog
)->action_area
);
637 length
= g_list_length(action_area
->children
);
640 IRRECO_ERROR("Cant get button \"%i\". "
641 "Dialog has only \"%i\" buttons", n
, length
);
642 IRRECO_RETURN_PTR(NULL
);
645 box_child
= (GtkBoxChild
*) g_list_nth_data(g_list_first(
646 action_area
->children
), n
);
647 IRRECO_RETURN_PTR(box_child
->widget
);
650 GtkWindow
*irreco_gtk_get_parent_window(GtkWidget
*widget
)
655 parent
= gtk_widget_get_toplevel(widget
);
656 if (GTK_WIDGET_TOPLEVEL(parent
) != TRUE
657 || GTK_IS_WINDOW(parent
) != TRUE
) {
658 IRRECO_RETURN_PTR(GTK_WINDOW(parent
));
660 IRRECO_RETURN_PTR(NULL
);
664 * This function is a modified version of gtk_dialog_new_empty() from GTK
665 * sources, which is used to by gtk_dialog_new_with_buttons() to set the
666 * settings of a dialog.
668 void irreco_gtk_dialog_set(GtkDialog
*dialog
,
671 GtkDialogFlags flags
)
676 gtk_window_set_title(GTK_WINDOW (dialog
), title
);
679 gtk_window_set_transient_for(GTK_WINDOW (dialog
), parent
);
681 if (flags
& GTK_DIALOG_MODAL
)
682 gtk_window_set_modal(GTK_WINDOW (dialog
), TRUE
);
684 if (flags
& GTK_DIALOG_DESTROY_WITH_PARENT
)
685 gtk_window_set_destroy_with_parent(GTK_WINDOW (dialog
), TRUE
);
687 if (flags
& GTK_DIALOG_NO_SEPARATOR
)
688 gtk_dialog_set_has_separator(dialog
, FALSE
);
695 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
697 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
700 * Difference of time in microseconds between two GTimeVals.
701 * This works fine as long as the difference is no more than 2146 seconds.
703 glong
irreco_time_diff(GTimeVal
*start
, GTimeVal
*end
)
708 diff
.tv_sec
= end
->tv_sec
- start
->tv_sec
;
709 diff
.tv_usec
= end
->tv_usec
- start
->tv_usec
;
711 /* We run out of space in ulong after 2147 seconds. */
712 if (diff
.tv_sec
>= G_MAXLONG
/ IRRECO_SECOND_IN_USEC
) {
713 IRRECO_RETURN_LONG((G_MAXLONG
/ IRRECO_SECOND_IN_USEC
)
714 * IRRECO_SECOND_IN_USEC
);
717 IRRECO_RETURN_LONG(diff
.tv_sec
* IRRECO_SECOND_IN_USEC
+ diff
.tv_usec
);
722 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
724 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
727 * Check if the socket is valid.
729 gboolean
irreco_is_socket_valid(int socket
)
736 /* This should succeed if socket is valid. */
737 rvalue
= getsockopt(socket
, SOL_SOCKET
, SOCK_STREAM
, &optval
, &optlen
);
740 IRRECO_RETURN_BOOL(TRUE
);
743 /* glibc docs say these are the possible error values. */
745 case EBADF
: IRRECO_PRINTF("Error: EBADF\n"); break;
746 case ENOTSOCK
: IRRECO_PRINTF("Error: ENOTSOCK\n"); break;
747 case ENOPROTOOPT
: IRRECO_PRINTF("Error: ENOPROTOOPT\n"); break;
748 default: IRRECO_PRINTF("Error: Unknown\n"); break;
751 IRRECO_RETURN_BOOL(FALSE
);