Changed style browser to search buttons only from subdirectories.
[irreco.git] / irreco / trunk / src / util / irreco_misc.c
blobcaa2ebb72fff2133421cf74bc272c8fcd241d652
1 /*
2 * irreco - Ir Remote Control
3 * Copyright (C) 2007 Arto Karppinen (arto.karppinen@iki.fi),
4 * Harri Vattulainen (t5vaha01@students.oamk.fi)
5 *
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>
25 #include <errno.h>
30 * Utility functions.
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 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
42 /**
43 * Check if the given filename is a directory.
45 int irreco_is_dir(const char *filename)
47 int rval;
48 struct stat buf;
49 char *realpath = canonicalize_file_name(filename);
50 rval = (realpath != NULL) &&
51 (stat(filename, &buf) == 0) &&
52 S_ISDIR(buf.st_mode);
53 free(realpath);
54 return rval;
57 /**
58 * Check if a given file is a regular file.
60 int irreco_is_file(const char *filename)
62 int rval;
63 struct stat buf;
64 char *realpath = canonicalize_file_name(filename);
65 rval = (realpath != NULL) &&
66 (stat(filename, &buf) == 0) &&
67 S_ISREG(buf.st_mode);
68 free(realpath);
69 return rval;
72 /**
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) {
79 return TRUE;
81 return FALSE;
84 /**
85 * Write data to file.
87 gboolean irreco_write_file(const gchar * file, const gchar * data,
88 gsize data_size)
90 FILE *handle;
91 size_t written;
92 IRRECO_ENTER
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);
100 fclose(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,
116 gsize buffer_size)
118 gint count;
119 FILE *fd;
121 buffer[0] = '\0';
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;
126 return TRUE;
130 * Read a line of text from file to buffer.
132 gboolean irreco_read_line(const gchar * file, gchar *buffer,
133 gsize buffer_size)
135 gint i;
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') {
140 buffer[i] = '\0';
141 return TRUE;
144 return TRUE;
148 * Write GKeyFile contents to file.
150 gboolean irreco_write_keyfile(GKeyFile * keyfile, const gchar * file)
152 gchar *data;
153 gsize data_size;
154 GError *error = NULL;
155 gboolean success;
156 IRRECO_ENTER
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);
164 g_free(data);
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;
175 GDir* dir = NULL;
176 IRRECO_ENTER
178 /* Open Dir. */
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);
183 g_dir_close(dir);
184 IRRECO_RETURN_BOOL(FALSE);
187 /* Read dir. */
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);
193 callback(dir_data);
194 g_free((void*)dir_data->filepath);
197 g_dir_close(dir);
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;
211 GDir* dir = NULL;
212 GDir* subdir = NULL;
213 const gchar *subpath = NULL;
214 const gchar *buttonsdir;
215 const gchar *directorykeeper = dir_data->directory;
216 IRRECO_ENTER
218 /* Open Dir. */
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,
230 buttonsdir, NULL);
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))
243 != NULL) {
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("/",
250 subpath,
251 dir_data->filename,
252 NULL);
253 dir_data->directory = subpath;
254 callback(dir_data);
255 dir_data->directory = directorykeeper;
256 g_free((void*)dir_data->filepath);
260 g_free((void*)subpath);
262 g_dir_close(dir);
263 g_dir_close(subdir);
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;
277 gchar *home;
278 gchar *apphome;
279 IRRECO_ENTER
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);
292 g_free(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)
303 gchar *config_dir;
304 gchar *config_file;
305 IRRECO_ENTER
307 if ((config_dir = irreco_get_config_dir(app_name)) != NULL) {
308 config_file = g_build_path("/", config_dir, file, NULL);
309 g_free(config_dir);
310 IRRECO_RETURN_PTR(config_file);
312 IRRECO_RETURN_PTR(NULL);
317 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
318 /* Strings. */
319 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
322 * Replace characters.
324 void irreco_char_replace(gchar * string, gchar what, gchar with)
326 gint i;
327 IRRECO_ENTER
328 for (i = 0; string[i] != '\0'; i++) {
329 if (string[i] == what) {
330 string[i] = with;
333 IRRECO_RETURN
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)
343 gint i;
344 IRRECO_ENTER
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:
358 * @li NULL
359 * @li ""
360 * @li Full of space characters.
362 gboolean irreco_str_isempty(const gchar * string)
364 IRRECO_ENTER
366 if (string == NULL || string[0] == '\0') IRRECO_RETURN_BOOL(TRUE);
367 do {
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)
383 IRRECO_ENTER
385 if (c_str == NULL) {
386 g_string_assign(g_str, "");
387 } else {
388 g_string_assign(g_str, c_str);
391 IRRECO_RETURN
395 * Copy C-string into GString and free C-string.
397 void irreco_gstring_set_and_free(GString * g_str, gchar * c_str)
399 IRRECO_ENTER
401 if (c_str == NULL) {
402 g_string_assign(g_str, "");
403 } else {
404 g_string_assign(g_str, c_str);
405 g_free(c_str);
408 IRRECO_RETURN
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);
426 *error = NULL;
427 return TRUE;
429 return FALSE;
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);
440 *error = NULL;
441 return TRUE;
443 return FALSE;
448 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
449 /* GTK. */
450 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
453 * Show info popup.
455 void irreco_info_dlg(GtkWindow * parent_window, const gchar * message)
457 GtkWidget* dialog;
458 IRRECO_ENTER
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);
466 IRRECO_RETURN
470 * Show error popup.
472 void irreco_error_dlg(GtkWindow * parent_window, const gchar * message)
474 GtkWidget* dialog;
475 IRRECO_ENTER
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);
483 IRRECO_RETURN
487 * Format message, and show error popup.
489 void irreco_info_dlg_printf(GtkWindow * parent_window,
490 const gchar * format, ...)
492 gint rvalue;
493 va_list args;
494 gchar *message = NULL;
495 IRRECO_ENTER
497 va_start(args, format);
498 rvalue = g_vasprintf(&message, format, args);
499 va_end(args);
501 if (rvalue > 0) {
502 irreco_info_dlg(parent_window, message);
503 g_free(message);
504 } else {
505 IRRECO_ERROR("Could not format message.\n");
508 IRRECO_RETURN
512 * Format message, and show error popup.
514 void irreco_error_dlg_printf(GtkWindow * parent_window,
515 const gchar * format, ...)
517 gint rvalue;
518 va_list args;
519 gchar *message = NULL;
520 IRRECO_ENTER
522 va_start(args, format);
523 rvalue = g_vasprintf(&message, format, args);
524 va_end(args);
526 if (rvalue > 0) {
527 irreco_error_dlg(parent_window, message);
528 g_free(message);
529 } else {
530 IRRECO_ERROR("Could not format message.\n");
533 IRRECO_RETURN
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)
543 gint responce;
544 GtkWidget* dialog;
545 IRRECO_ENTER
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,
559 gfloat xalign,
560 gfloat yalign,
561 gfloat xscale,
562 gfloat yscale,
563 guint padding_top,
564 guint padding_bottom,
565 guint padding_left,
566 guint padding_right)
568 GtkWidget *align;
569 IRRECO_ENTER
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,
582 gfloat xalign,
583 gfloat yalign,
584 guint padding_top,
585 guint padding_bottom,
586 guint padding_left,
587 guint padding_right)
589 GtkWidget *label;
590 IRRECO_ENTER
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,
602 gfloat xalign,
603 gfloat yalign,
604 guint padding_top,
605 guint padding_bottom,
606 guint padding_left,
607 guint padding_right)
609 gchar* markup;
610 GtkWidget *label;
611 IRRECO_ENTER
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))),
617 markup);
618 g_free(markup);
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)
631 GtkBox *action_area;
632 GtkBoxChild *box_child;
633 guint length;
634 IRRECO_ENTER
636 action_area = GTK_BOX(GTK_DIALOG(dialog)->action_area);
637 length = g_list_length(action_area->children);
639 if (n >= length) {
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)
652 GtkWidget *parent;
653 IRRECO_ENTER
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,
669 const gchar *title,
670 GtkWindow *parent,
671 GtkDialogFlags flags)
673 IRRECO_ENTER
675 if (title)
676 gtk_window_set_title(GTK_WINDOW (dialog), title);
678 if (parent)
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);
690 IRRECO_RETURN
695 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
696 /* Time. */
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)
705 GTimeVal diff;
706 IRRECO_ENTER
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 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
723 /* Socket. */
724 /*=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-*/
727 * Check if the socket is valid.
729 gboolean irreco_is_socket_valid(int socket)
731 gint optval;
732 socklen_t optlen;
733 gint rvalue;
734 IRRECO_ENTER
736 /* This should succeed if socket is valid. */
737 rvalue = getsockopt(socket, SOL_SOCKET, SOCK_STREAM, &optval, &optlen);
739 if (rvalue == 0) {
740 IRRECO_RETURN_BOOL(TRUE);
741 } else {
743 /* glibc docs say these are the possible error values. */
744 switch (errno) {
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);