/** * @file utils.cc * @copyright (C) 2001-2006 Marcus Bjurman\n * @copyright (C) 2007-2012 Piotr Eljasiak\n * @copyright (C) 2013-2023 Uwe Scholz\n * * @copyright This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * @copyright This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * @copyright You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include "gnome-cmd-includes.h" #include "utils.h" #include "gnome-cmd-data.h" #include "imageloader.h" #include "gnome-cmd-main-win.h" #include "gnome-cmd-user-actions.h" using namespace std; #define FIX_PW_HACK #define STRINGS_TO_URIS_CHUNK 1024 static GdkCursor *cursor_busy = NULL; static gchar *tmp_file_dir = NULL; /** * The already reserved debug flags: * -------------------------------- * a: set all debug flags\n * c: file and directory counting\n * d: directory ref-counting\n * f: file ref-counting\n * g: run_command debugging\n * i: imageloader\n * k: directory pool\n * l: directory listings\n * m: connection debugging\n * n: directory monitoring\n * s: smb network browser\n * t: metadata tags\n * u: user actions debugging\n * v: internal viewer\n * w: widget_lookup\n * y: brief mime-based imageload\n * z: detailed mime-based imageload\n * x: xfer */ void DEBUG (gchar flag, const gchar *format, ...) { if (DEBUG_ENABLED (flag)) { va_list ap; va_start(ap, format); fprintf (stderr, "[%c%c] ", flag-32, flag-32); vfprintf(stderr, format, ap); va_end(ap); } } /** * This function executes a command in the active directory in a * terminal window, if desired. * \param in_command Command to be executed. * \param dpath Directory in which the command should be executed. * \param term If TRUE, the command is executed in a terminal window. * \sa GnomeCmdData::Options::termexec */ gboolean run_command_indir (const gchar *in_command, const gchar *dpath, gboolean term) { g_return_val_if_fail (in_command != NULL, FALSE); g_return_val_if_fail (strlen(in_command) != 0, FALSE); gchar *command; if (term) { gchar *arg; if (gnome_cmd_data.use_gcmd_block) { gchar *s = g_strdup_printf ("bash -c \"%s; %s/bin/gcmd-block\"", in_command, PREFIX); arg = g_shell_quote (s); g_free (s); } else arg = g_shell_quote (in_command); #if defined (__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wformat-nonliteral" #endif command = g_strdup_printf (gnome_cmd_data.options.termexec, arg); #if defined (__GNUC__) #pragma GCC diagnostic pop #endif g_free (arg); } else command = g_strdup (in_command); DEBUG ('g', "running%s: %s\n", (term?" in terminal":""), command); gint argc; gchar **argv; GError *error = NULL; // check if command includes % and replace string cmd; cmd.reserve(2000); if (parse_command(&cmd, (const gchar*) command) == 0) { DEBUG ('g', "run_command_indir: command is not valid.\n"); gnome_cmd_show_message (*main_win, _("No valid command given.")); return FALSE; } //g_shell_parse_argv (command, &argc, &argv, NULL); g_shell_parse_argv (cmd.c_str(), &argc, &argv, NULL); // include parse_command if (!g_spawn_async (dpath, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error)) { gnome_cmd_error_message (_("Unable to execute command."), error); g_strfreev (argv); g_free (command); return FALSE; } g_strfreev (argv); g_free (command); return TRUE; } const char **convert_varargs_to_name_array (va_list args) { const char *name; GPtrArray *resizeable_array = g_ptr_array_new (); do { name = va_arg (args, const char *); g_ptr_array_add (resizeable_array, (gpointer) name); } while (name); const char **plain_ole_array = (const char **) resizeable_array->pdata; g_ptr_array_free (resizeable_array, FALSE); return plain_ole_array; } static gboolean delete_event_callback (gpointer data, gpointer user_data) { g_return_val_if_fail (GTK_IS_DIALOG (data), FALSE); g_signal_stop_emission_by_name (data, "delete-event"); return TRUE; } static gboolean on_run_dialog_keypress (GtkWidget *dialog, GdkEventKey *event, gpointer data) { if (event->keyval == GDK_Escape) { gtk_dialog_response (GTK_DIALOG (dialog), GTK_RESPONSE_NONE); return TRUE; } return FALSE; } gint run_simple_dialog (GtkWidget *parent, gboolean ignore_close_box, GtkMessageType msg_type, const char *text, const char *title, gint def_response, ...) { va_list button_title_args; const char **button_titles; GtkWidget *dialog; // GtkWidget *top_widget; int result; // Create the dialog. va_start (button_title_args, def_response); button_titles = convert_varargs_to_name_array (button_title_args); va_end (button_title_args); dialog = gtk_message_dialog_new (*main_win, GTK_DIALOG_MODAL, msg_type, GTK_BUTTONS_NONE, NULL); gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), text); if (title) gtk_window_set_title (GTK_WINDOW (dialog), title); for (int i=0; button_titles[i]; i++) gtk_dialog_add_button (GTK_DIALOG (dialog), button_titles[i], i); g_free (button_titles); if (def_response>=0) gtk_dialog_set_default_response (GTK_DIALOG (dialog), def_response); // Allow close. if (ignore_close_box) g_signal_connect (dialog, "delete-event", G_CALLBACK (delete_event_callback), NULL); else g_signal_connect (dialog, "key-press-event", G_CALLBACK (on_run_dialog_keypress), dialog); gtk_window_set_wmclass (GTK_WINDOW (dialog), "dialog", "Eel"); // Run it. do { gtk_widget_show (dialog); result = gtk_dialog_run (GTK_DIALOG (dialog)); } while (ignore_close_box && result == GTK_RESPONSE_DELETE_EVENT); gtk_widget_destroy (dialog); return result; } const gchar *type2string (guint32 type, gchar *buf, guint max) { const char *s; switch (type) { case G_FILE_TYPE_UNKNOWN: s = "?"; break; case G_FILE_TYPE_REGULAR: s = " "; break; case G_FILE_TYPE_DIRECTORY: s = G_DIR_SEPARATOR_S; break; case G_FILE_TYPE_SYMBOLIC_LINK: s = "@"; break; case G_FILE_TYPE_SPECIAL: s = "S"; break; case G_FILE_TYPE_SHORTCUT: s = "K"; // "Keyboard shortcut" break; case G_FILE_TYPE_MOUNTABLE: s = "M"; break; default: s = "?"; } g_snprintf (buf, max, "%s", s); return buf; } const gchar *perm2string (guint32 permissions, gchar *buf, guint max) { switch (gnome_cmd_data.options.perm_disp_mode) { case GNOME_CMD_PERM_DISP_MODE_TEXT: return perm2textstring (permissions, buf, max); case GNOME_CMD_PERM_DISP_MODE_NUMBER: return perm2numstring (permissions, buf, max); default: return perm2textstring (permissions, buf, max); } } const gchar *perm2textstring (guint32 permissions, gchar *buf, guint max) { g_snprintf (buf, max, "%s%s%s%s%s%s%s%s%s", (permissions & GNOME_CMD_PERM_USER_READ) ? "r" : "-", (permissions & GNOME_CMD_PERM_USER_WRITE) ? "w" : "-", (permissions & GNOME_CMD_PERM_USER_EXEC) ? "x" : "-", (permissions & GNOME_CMD_PERM_GROUP_READ) ? "r" : "-", (permissions & GNOME_CMD_PERM_GROUP_WRITE) ? "w" : "-", (permissions & GNOME_CMD_PERM_GROUP_EXEC) ? "x" : "-", (permissions & GNOME_CMD_PERM_OTHER_READ) ? "r" : "-", (permissions & GNOME_CMD_PERM_OTHER_WRITE) ? "w" : "-", (permissions & GNOME_CMD_PERM_OTHER_EXEC) ? "x" : "-"); return buf; } const gchar *perm2numstring (guint32 permissions, gchar *buf, guint max) { gint i = 0; if (permissions & GNOME_CMD_PERM_USER_READ) i += 400; if (permissions & GNOME_CMD_PERM_USER_WRITE) i += 200; if (permissions & GNOME_CMD_PERM_USER_EXEC) i += 100; if (permissions & GNOME_CMD_PERM_GROUP_READ) i += 40; if (permissions & GNOME_CMD_PERM_GROUP_WRITE) i += 20; if (permissions & GNOME_CMD_PERM_GROUP_EXEC) i += 10; if (permissions & GNOME_CMD_PERM_OTHER_READ) i += 4; if (permissions & GNOME_CMD_PERM_OTHER_WRITE) i += 2; if (permissions & GNOME_CMD_PERM_OTHER_EXEC) i += 1; g_snprintf (buf, max, "%i", i); return buf; } const gchar *size2string (guint64 size, GnomeCmdSizeDispMode size_disp_mode) { static gchar buf0[64]; static gchar buf1[128]; switch (size_disp_mode) { case GNOME_CMD_SIZE_DISP_MODE_POWERED: { static const gchar *prefixes[] = {"B","kB","MB","GB","TB","PB"}; gdouble dsize = (gdouble) size; guint i; for (i=0; i1024; i++) dsize /= 1024; if (i) g_snprintf (buf0, sizeof(buf0), "%.1f %s ", dsize, prefixes[i]); else g_snprintf (buf0, sizeof(buf0), "%" G_GUINT64_FORMAT " %s ", size, prefixes[0]); } break; case GNOME_CMD_SIZE_DISP_MODE_GROUPED: { gint len = g_snprintf (buf0, sizeof(buf0), "%" G_GUINT64_FORMAT " ", size); if (len < 5) return buf0; gchar *sep = (gchar*) " "; gchar *src = buf0; gchar *dest = buf1; *dest++ = *src++; for (gint i=len; i>0; i--) { if (i>2 && i%3 == 2) dest = g_stpcpy (dest, sep); *dest++ = *src++; } } return buf1; case GNOME_CMD_SIZE_DISP_MODE_LOCALE: g_snprintf (buf0, sizeof(buf0), "%'" G_GUINT64_FORMAT " ", size); break; case GNOME_CMD_SIZE_DISP_MODE_PLAIN: g_snprintf (buf0, sizeof(buf0), "%" G_GUINT64_FORMAT " ", size); break; default: break; } return buf0; } const gchar *time2string (GDateTime *gDateTime, const gchar *dateFormat) { // NOTE: date_format is passed in current locale format g_return_val_if_fail (gDateTime != nullptr, nullptr); g_return_val_if_fail (dateFormat != nullptr, nullptr); static gchar buf[64]; auto localGDateTime = g_date_time_to_local (gDateTime); auto dateString = g_date_time_format (localGDateTime, dateFormat); strncpy (buf, dateString, sizeof(buf)-1); g_date_time_unref(localGDateTime); g_free (dateString); return buf; } void clear_event_key (GdkEventKey *event) { g_return_if_fail (event != NULL); g_return_if_fail (event->string != NULL); event->keyval = GDK_VoidSymbol; event->string[0] = '\0'; } /** * Transform a "\r\n" separated string into a GList with GFiles's */ GList *uri_strings_to_gfiles (gchar *data) { GList *gFileGList = NULL; gchar **filenames = g_strsplit (data, "\r\n", STRINGS_TO_URIS_CHUNK); for (gint i=0; filenames[i] != NULL; i++) { if (i == STRINGS_TO_URIS_CHUNK) { gFileGList = g_list_concat (gFileGList, uri_strings_to_gfiles (filenames[i])); break; } gchar *fn = g_strdup (filenames[i]); if (!fn || strcmp(fn, "") == 0) { g_free(fn); continue; } auto gFile = g_file_new_for_uri(fn); gFileGList = g_list_append (gFileGList, gFile); g_free (fn); } g_strfreev (filenames); return gFileGList; } GList *string_history_add (GList *in, const gchar *value, guint maxsize) { GList *tmp = g_list_find_custom (in, (gchar *) value, (GCompareFunc) strcmp); GList *out; // if the same value has been given before move it first in the list if (tmp != NULL) { out = g_list_remove_link (in, tmp); tmp->next = out; if (out) out->prev = tmp; out = tmp; } // or if its new just add it else out = g_list_prepend (in, g_strdup (value)); // don't let the history get too long while (g_list_length (out) > maxsize) { tmp = g_list_last (out); g_free (tmp->data); out = g_list_remove_link (out, tmp); } return out; } gchar *create_nice_size_str (guint64 size) { GString *s = g_string_sized_new (64); if (gnome_cmd_data.options.size_disp_mode==GNOME_CMD_SIZE_DISP_MODE_POWERED && size>=1000) { g_string_printf (s, "%s", size2string (size, GNOME_CMD_SIZE_DISP_MODE_POWERED)); g_string_append_printf (s, ngettext("(%sbyte)","(%sbytes)",size), size2string (size, GNOME_CMD_SIZE_DISP_MODE_GROUPED)); } else g_string_printf (s, ngettext("%sbyte","%sbytes",size), size2string (size, GNOME_CMD_SIZE_DISP_MODE_GROUPED)); return g_string_free (s, FALSE); } gchar *unquote_if_needed (const gchar *in) { g_return_val_if_fail (in != NULL, NULL); gint l = strlen (in); // Check if the first and last character is a quote if (l>1 && strchr("'\"",in[0])!=NULL && in[0]==in[l-1]) { gchar *out = g_strdup (in+1); out[l-2] = '\0'; return out; } return g_strdup (in); } GtkWidget *create_styled_button (const gchar *text) { GtkWidget *w = text ? gtk_button_new_with_label (text) : gtk_button_new (); gtk_button_set_relief (GTK_BUTTON (w), GTK_RELIEF_NONE); g_object_ref (w); gtk_widget_show (w); return w; } GtkWidget *create_styled_pixmap_button (const gchar *text, GnomeCmdPixmap *pm) { g_return_val_if_fail (text || pm, NULL); GtkWidget *btn = create_styled_button (NULL); GtkWidget *hbox = gtk_hbox_new (FALSE, 1); GtkWidget *label = NULL; GtkWidget *image = NULL; g_object_set_data_full (G_OBJECT (btn), "hbox", hbox, g_object_unref); g_object_ref (hbox); gtk_widget_show (hbox); if (pm) { image = gtk_image_new_from_pixmap (pm->pixmap, pm->mask); if (image) { g_object_ref (image); g_object_set_data_full (G_OBJECT (btn), "image", image, g_object_unref); gtk_widget_show (image); } } if (text) { label = gtk_label_new (text); g_object_ref (label); g_object_set_data_full (G_OBJECT (btn), "label", label, g_object_unref); gtk_widget_show (label); } if (pm && !text) gtk_container_add (GTK_CONTAINER (btn), image); else if (!pm && text) gtk_container_add (GTK_CONTAINER (btn), label); else { gtk_box_pack_start (GTK_BOX (hbox), image, FALSE, TRUE, 0); gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); gtk_container_add (GTK_CONTAINER (btn), hbox); } return btn; } void set_cursor_busy_for_widget (GtkWidget *widget) { if (!cursor_busy) cursor_busy = gdk_cursor_new (GDK_WATCH); gdk_window_set_cursor (gtk_widget_get_window (widget), cursor_busy); while (gtk_events_pending ()) gtk_main_iteration(); } void set_cursor_busy () { set_cursor_busy_for_widget (*main_win); } void set_cursor_default () { set_cursor_default_for_widget (*main_win); } GList *app_get_linked_libs (GnomeCmdFile *f) { g_return_val_if_fail (GNOME_CMD_IS_FILE (f), NULL); gchar *s; gchar tmp[256]; gchar *arg = g_shell_quote (f->get_real_path()); gchar *cmd = g_strdup_printf ("ldd %s", arg); g_free (arg); FILE *fd = popen (cmd, "r"); g_free (cmd); if (!fd) return NULL; GList *libs = NULL; while ((s = fgets (tmp, sizeof(tmp), fd))) { char **v = g_strsplit (s, " ", 1); if (v) { libs = g_list_append (libs, g_strdup (v[0])); g_strfreev (v); } } pclose (fd); return libs; } gboolean app_needs_terminal (GnomeCmdFile *f) { gboolean needTerminal; auto contentType = f->GetGfileAttributeString(G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE); if (strcmp (contentType, "application/x-executable") && strcmp (contentType, "application/x-executable-binary")) { needTerminal = TRUE; } else { GList *libs = app_get_linked_libs (f); if (!libs) { needTerminal = FALSE; } else { for (GList *i = libs; i; i = i->next) { gchar *lib = (gchar *) i->data; lib = g_strstrip (lib); if (g_str_has_prefix (lib, "libX11")) { needTerminal = FALSE; break; } } } g_list_foreach (libs, (GFunc) g_free, NULL); g_list_free (libs); } g_free(contentType); return needTerminal; } // ToDo: This function should be reworked using GIO / GFile gchar *get_temp_download_filepath (const gchar *fname) { const gchar *tmp_dir = g_get_tmp_dir (); if (!tmp_file_dir) { if (chdir (tmp_dir)) { gnome_cmd_show_message (NULL, _("Failed to change working directory to a temporary directory."), strerror (errno)); return NULL; } gchar *tmp_file_dir_template = g_strdup_printf ("gcmd-%s-XXXXXX", g_get_user_name()); tmp_file_dir = mkdtemp (tmp_file_dir_template); if (!tmp_file_dir) { g_free (tmp_file_dir_template); gnome_cmd_show_message (NULL, _("Failed to create a directory in which to store temporary files."), strerror (errno)); return NULL; } } return g_build_filename (tmp_dir, tmp_file_dir, fname, NULL); } void remove_temp_download_dir () { if (tmp_file_dir) { gchar *path = g_build_filename (g_get_tmp_dir (), tmp_file_dir, NULL); gchar *command = g_strdup_printf ("rm -rf %s", path); g_free (path); int status; if ((status = system (command))) { g_warning ("executing \"%s\" failed with exit status %d\n", command, status); } g_free (command); } } inline GtkWidget *scale_pixbuf (GdkPixbuf *pixbuf, GtkIconSize icon_size) { int width, height; gtk_icon_size_lookup (icon_size, &width, &height); double pix_x = gdk_pixbuf_get_width (pixbuf); double pix_y = gdk_pixbuf_get_height (pixbuf); // Only scale if the image doesn't match the required icon size if (pix_x > width || pix_y > height) { double greatest = pix_x > pix_y ? pix_x : pix_y; GdkPixbuf *scaled = gdk_pixbuf_scale_simple (pixbuf, (width/ greatest) * pix_x, (height/ greatest) * pix_y, GDK_INTERP_BILINEAR); GtkWidget *image = gtk_image_new_from_pixbuf (scaled); g_object_unref (scaled); return image; } return gtk_image_new_from_pixbuf (pixbuf); } inline void transform (gchar *s, gchar from, gchar to) { gint len = strlen (s); for (gint i=0; ipixel = 0; c->red = r; c->green = g; c->blue = b; return c; } GList *gnome_cmd_file_list_to_gfile_list (GList *files) { GList *gFiles = nullptr; for (; files; files = files->next) { GnomeCmdFile *f = GNOME_CMD_FILE (files->data); auto gFile = f->get_gfile(); if (!gFile) g_warning ("gnome_cmd_file_list_to_gfile_list: no gFile!!!"); else gFiles = g_list_append (gFiles, gFile); } return gFiles; } gboolean is_dir_existing(const gchar *dpath) { g_return_val_if_fail (dpath, FALSE); auto gFile = g_file_new_for_path(dpath); auto returnValue = false; if (g_file_query_exists(gFile, nullptr)) { returnValue = true; } g_object_unref(gFile); return returnValue; } gboolean create_dir (const gchar *dpath) { g_return_val_if_fail (dpath, FALSE); g_print (_("Creating directory %s… "), dpath); GError *error = nullptr; auto gFile = g_file_new_for_path(dpath); if (g_file_make_directory (gFile, nullptr, &error)) { g_object_unref(gFile); return TRUE; } else { g_object_unref(gFile); g_warning (_("Failed to create the directory %s: %s"), dpath, error->message); g_error_free (error); return FALSE; } } GList *patlist_new (const gchar *pattern_string) { g_return_val_if_fail (pattern_string != NULL, NULL); GList *patlist = NULL; gchar **ents = g_strsplit (pattern_string, ";", 0); for (gint i = 0; ents[i]; i++) patlist = g_list_append (patlist, ents[i]); g_free (ents); return patlist; } void patlist_free (GList *pattern_list) { if (!pattern_list) return; g_list_foreach (pattern_list, (GFunc) g_free, NULL); g_list_free (pattern_list); } gboolean patlist_matches (GList *pattern_list, const gchar *s) { for (GList *i=pattern_list; i; i=i->next) #ifdef FNM_CASEFOLD if (fnmatch ((gchar *) i->data, s, FNM_NOESCAPE|FNM_CASEFOLD) == 0) #else if (fnmatch ((gchar *) i->data, s, FNM_NOESCAPE) == 0) // omit FNM_CASEFOLD as it is a GNU extension. #endif return TRUE; return FALSE; } void gnome_cmd_toggle_file_name_selection (GtkWidget *entry) { const gchar *text = gtk_entry_get_text (GTK_ENTRY (entry)); const char *s = strrchr(text,G_DIR_SEPARATOR); // G_DIR_SEPARATOR is ASCII, g_utf8_strrchr() is not needed here glong base = s ? g_utf8_pointer_to_offset (text, ++s) : 0; gint beg; gint end; if (!gtk_editable_get_selection_bounds (GTK_EDITABLE (entry), &beg, &end)) { beg = base; end = -1; } else { glong text_len = g_utf8_strlen (text, -1); s = strrchr(s ? s : text,'.'); // '.' is ASCII, g_utf8_strrchr() is not needed here glong ext = s ? g_utf8_pointer_to_offset (text, s) : -1; if (beg==0 && end==text_len) { beg = base; end = ext; } else { if (beg!=base) beg = beg>base ? base : 0; else if (end!=ext || end==text_len) beg = 0; end = -1; } } gtk_editable_select_region (GTK_EDITABLE (entry), beg, end); } void gnome_cmd_help_display (const gchar *file_name, const gchar *link_id) { GError *error = NULL; gchar help_uri[256] = "help:"; strcat(help_uri, PACKAGE_NAME); if (link_id != NULL) { strcat(help_uri, "/"); strcat(help_uri, link_id); } gtk_show_uri (NULL, help_uri, gtk_get_current_event_time (), &error); if (error != NULL) gnome_cmd_error_message (_("There was an error displaying help."), error); } void gnome_cmd_error_message (const gchar *title, GError *error) { gnome_cmd_prompt_message (NULL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, title, error->message); g_error_free (error); } gboolean gnome_cmd_prepend_su_to_vector (int &argc, char **&argv) { // sanity if(!argv) argc = 0; char *su = NULL; gboolean need_c = FALSE; if ((su = g_find_program_in_path ("gksudo"))) goto without_c_param; if ((su = g_find_program_in_path ("xdg-su"))) goto without_c_param; if ((su = g_find_program_in_path ("gksu"))) goto without_c_param; if ((su = g_find_program_in_path ("gnomesu"))) goto with_c_param; if ((su = g_find_program_in_path ("beesu"))) goto without_c_param; if ((su = g_find_program_in_path ("kdesu"))) goto without_c_param; return FALSE; with_c_param: need_c = TRUE; without_c_param: char **su_argv = g_new0 (char *, 3); int su_argc = 0; su_argv[su_argc++] = su; if (need_c) su_argv[su_argc++] = g_strdup("-c"); // compute size if not given if (argc < 0) for (argc=0; argv[argc]; ++argc); int real_argc = su_argc + argc; char **real_argv = g_new0 (char *, real_argc+1); memmove (real_argv, su_argv, su_argc*sizeof(char *)); memmove (real_argv+su_argc, argv, argc*sizeof(char *)); g_free (argv); argv = real_argv; argc = real_argc; return TRUE; } int split(const string &s, vector &coll, const char *sep) { coll.clear(); if (s.empty()) return 0; if (!sep) sep = ""; int seplen = strlen(sep); if (!seplen) { for (string::const_iterator i=s.begin(); i!=s.end(); ++i) coll.push_back(string(1,*i)); return s.length(); } int n = 1; int start = 0; for (int end; (size_t)(end=s.find(sep,start))!=string::npos; ++n) { coll.push_back(string(s,start,end-start)); start = end + seplen; } coll.push_back(string(s,start)); return n; } gint get_string_pixel_size (const char *s, int len) { // find the size, in pixels, of the given string gint xSize, ySize; gchar *buf = g_strndup(s, len); gchar *utf8buf = get_utf8 (buf); GtkLabel *label = GTK_LABEL (gtk_label_new (utf8buf)); gchar *ms = get_mono_text (utf8buf); gtk_label_set_markup (label, ms); g_free (ms); g_object_ref_sink(G_OBJECT(label)); PangoLayout *layout = gtk_label_get_layout (label); pango_layout_get_pixel_size (layout, &xSize, &ySize); g_object_unref(GTK_OBJECT (label)); g_free (utf8buf); g_free (buf); return xSize; } gchar* get_package_config_dir() { return g_build_filename (g_get_user_config_dir(), PACKAGE, NULL); } gchar *string_double_underscores (const gchar *string) { if (!string) return nullptr; int underscores = 0; for (const gchar *p = string; *p; p++) underscores += (*p == '_'); if (underscores == 0) return g_strdup (string); gchar *escaped = g_new (char, strlen (string) + underscores + 1); gchar *q = escaped; for (const gchar *p = string; *p; p++, q++) { /* Add an extra underscore. */ if (*p == '_') *q++ = '_'; *q = *p; } *q = '\0'; return escaped; } guint32 get_gfile_attribute_uint32(GFileInfo *gFileInfo, const char *attribute) { g_return_val_if_fail(gFileInfo != nullptr, 0); g_return_val_if_fail(G_IS_FILE_INFO(gFileInfo), 0); return g_file_info_get_attribute_uint32 (gFileInfo, attribute); } guint32 get_gfile_attribute_uint32(GFile *gFile, const char *attribute) { GError *error; error = nullptr; guint32 gFileAttributeUInt32 = 0; auto gcmdFileInfo = g_file_query_info(gFile, attribute, G_FILE_QUERY_INFO_NONE, nullptr, &error); if (error) { auto gFileUri = g_file_get_uri(gFile); g_message ("get_gfile_attribute_uint32: retrieving file info for %s failed: %s", gFileUri, error->message); g_free(gFileUri); g_error_free (error); } else { gFileAttributeUInt32 = get_gfile_attribute_uint32 (gcmdFileInfo, attribute); g_object_unref(gcmdFileInfo); } return gFileAttributeUInt32; } guint64 get_gfile_attribute_uint64(GFileInfo *gFileInfo, const char *attribute) { g_return_val_if_fail(gFileInfo != nullptr, 0); g_return_val_if_fail(G_IS_FILE_INFO(gFileInfo), 0); return g_file_info_get_attribute_uint64 (gFileInfo, attribute); } guint64 get_gfile_attribute_uint64(GFile *gFile, const char *attribute) { GError *error; error = nullptr; guint64 gFileAttributeUInt64 = 0; auto gcmdFileInfo = g_file_query_info(gFile, attribute, G_FILE_QUERY_INFO_NONE, nullptr, &error); if (error) { auto gFileUri = g_file_get_uri(gFile); g_message ("get_gfile_attribute_uint64: retrieving file info for %s failed: %s", gFileUri, error->message); g_free(gFileUri); g_error_free (error); } else { gFileAttributeUInt64 = get_gfile_attribute_uint64 (gcmdFileInfo, attribute); g_object_unref(gcmdFileInfo); } return gFileAttributeUInt64; } gboolean get_gfile_attribute_boolean(GFileInfo *gFileInfo, const char *attribute) { g_return_val_if_fail(gFileInfo != nullptr, FALSE); g_return_val_if_fail(G_IS_FILE_INFO(gFileInfo), FALSE); return g_file_info_get_attribute_boolean (gFileInfo, attribute); } gboolean get_gfile_attribute_boolean(GFile *gFile, const char *attribute) { GError *error; error = nullptr; gboolean gFileAttributeBoolean = 0; auto gcmdFileInfo = g_file_query_info(gFile, attribute, G_FILE_QUERY_INFO_NONE, nullptr, &error); if (error) { auto gFileUri = g_file_get_uri(gFile); g_message ("get_gfile_attribute_boolean: retrieving file info for %s failed: %s", gFileUri, error->message); g_free(gFileUri); g_error_free (error); } else { gFileAttributeBoolean = get_gfile_attribute_boolean (gcmdFileInfo, attribute); g_object_unref(gcmdFileInfo); } return gFileAttributeBoolean; } gchar *get_gfile_attribute_string(GFileInfo *gFileInfo, const char *attribute) { g_return_val_if_fail(gFileInfo != nullptr, nullptr); g_return_val_if_fail(G_IS_FILE_INFO(gFileInfo), nullptr); return g_strdup(g_file_info_get_attribute_string (gFileInfo, attribute)); } gchar *get_gfile_attribute_string(GFile *gFile, const char *attribute) { GError *error; error = nullptr; auto gcmdFileInfo = g_file_query_info(gFile, attribute, G_FILE_QUERY_INFO_NONE, nullptr, &error); if (gcmdFileInfo && error) { auto gFileUri = g_file_get_uri(gFile); g_message ("get_gfile_attribute_string: retrieving file info for %s failed: %s", gFileUri, error->message); g_free(gFileUri); g_error_free (error); return nullptr; } auto gFileAttributeString = get_gfile_attribute_string (gcmdFileInfo, attribute); g_object_unref(gcmdFileInfo); return gFileAttributeString; }