/* * utils.c - this file is part of Geany, a fast and lightweight IDE * * Copyright 2005-2011 Enrico Tröger * Copyright 2006-2011 Nick Treleaven * * 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. * * 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. * * 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 Street, Fifth Floor, Boston, MA 02110-1301, USA. * * $Id$ */ /* * General utility functions, non-GTK related. */ #include "geany.h" #include #include #include #include #include #include #include #ifdef HAVE_SYS_STAT_H # include #endif #ifdef HAVE_SYS_TYPES_H # include #endif #include #include #include "prefs.h" #include "support.h" #include "document.h" #include "filetypes.h" #include "dialogs.h" #include "win32.h" #include "project.h" #include "ui_utils.h" #include "utils.h" /** * Tries to open the given URI in a browser. * On Windows, the system's default browser is opened. * On non-Windows systems, the browser command set in the preferences dialog is used. In case * that fails or it is unset, the user is asked to correct or fill it. * * @param uri The URI to open in the web browser. * * @since 0.16 **/ void utils_open_browser(const gchar *uri) { #ifdef G_OS_WIN32 g_return_if_fail(uri != NULL); win32_open_browser(uri); #else gboolean again = TRUE; g_return_if_fail(uri != NULL); while (again) { gchar *cmdline = g_strconcat(tool_prefs.browser_cmd, " \"", uri, "\"", NULL); if (g_spawn_command_line_async(cmdline, NULL)) again = FALSE; else { gchar *new_cmd = dialogs_show_input(_("Select Browser"), GTK_WINDOW(main_widgets.window), _("Failed to spawn the configured browser command. " "Please correct it or enter another one."), tool_prefs.browser_cmd); if (new_cmd == NULL) /* user canceled */ again = FALSE; else setptr(tool_prefs.browser_cmd, new_cmd); } g_free(cmdline); } #endif } /* taken from anjuta, to determine the EOL mode of the file */ gint utils_get_line_endings(const gchar* buffer, gsize size) { gsize i; guint cr, lf, crlf, max_mode; gint mode; cr = lf = crlf = 0; for (i = 0; i < size ; i++) { if (buffer[i] == 0x0a) { /* LF */ lf++; } else if (buffer[i] == 0x0d) { if (i >= (size - 1)) { /* Last char, CR */ cr++; } else { if (buffer[i + 1] != 0x0a) { /* CR */ cr++; } else { /* CRLF */ crlf++; } i++; } } } /* Vote for the maximum */ mode = SC_EOL_LF; max_mode = lf; if (crlf > max_mode) { mode = SC_EOL_CRLF; max_mode = crlf; } if (cr > max_mode) { mode = SC_EOL_CR; max_mode = cr; } return mode; } gboolean utils_isbrace(gchar c, gboolean include_angles) { switch (c) { case '<': case '>': return include_angles; case '(': case ')': case '{': case '}': case '[': case ']': return TRUE; default: return FALSE; } } gboolean utils_is_opening_brace(gchar c, gboolean include_angles) { switch (c) { case '<': return include_angles; case '(': case '{': case '[': return TRUE; default: return FALSE; } } /** * Writes @a text into a file named @a filename. * If the file doesn't exist, it will be created. * If it already exists, it will be overwritten. * * @warning You should use @c g_file_set_contents() instead if you don't need * file permissions and other metadata to be preserved, as that always handles * disk exhaustion safely. * * @param filename The filename of the file to write, in locale encoding. * @param text The text to write into the file. * * @return 0 if the file was successfully written, otherwise the @c errno of the * failed operation is returned. **/ gint utils_write_file(const gchar *filename, const gchar *text) { g_return_val_if_fail(filename != NULL, ENOENT); g_return_val_if_fail(text != NULL, EINVAL); if (file_prefs.use_safe_file_saving) { GError *error = NULL; if (! g_file_set_contents(filename, text, -1, &error)) { geany_debug("%s: could not write to file %s (%s)", G_STRFUNC, filename, error->message); g_error_free(error); return EIO; } } else { FILE *fp; gsize bytes_written, len; gboolean fail = FALSE; if (filename == NULL) return ENOENT; len = strlen(text); errno = 0; fp = g_fopen(filename, "w"); if (fp == NULL) fail = TRUE; else { bytes_written = fwrite(text, sizeof(gchar), len, fp); if (len != bytes_written) { fail = TRUE; geany_debug( "utils_write_file(): written only %"G_GSIZE_FORMAT" bytes, had to write %"G_GSIZE_FORMAT" bytes to %s", bytes_written, len, filename); } if (fclose(fp) != 0) fail = TRUE; } if (fail) { geany_debug("utils_write_file(): could not write to file %s (%s)", filename, g_strerror(errno)); return NVL(errno, EIO); } } return 0; } /** Searches backward through @a size bytes looking for a '<'. * @param sel . * @param size . * @return The tag name (newly allocated) or @c NULL if no opening tag was found. */ gchar *utils_find_open_xml_tag(const gchar sel[], gint size) { const gchar *cur, *begin; gsize len; cur = utils_find_open_xml_tag_pos(sel, size); if (cur == NULL) return NULL; cur++; /* skip the bracket */ begin = cur; while (strchr(":_-.", *cur) || isalnum(*cur)) cur++; len = (gsize)(cur - begin); return len ? g_strndup(begin, len) : NULL; } /** Searches backward through @a size bytes looking for a '<'. * @param sel . * @param size . * @return pointer to '<' of the found opening tag within @a sel, or @c NULL if no opening tag was found. */ const gchar *utils_find_open_xml_tag_pos(const gchar sel[], gint size) { /* stolen from anjuta and modified */ const gchar *begin, *cur; if (G_UNLIKELY(size < 3)) { /* Smallest tag is "

" which is 3 characters */ return NULL; } begin = &sel[0]; cur = &sel[size - 1]; /* Skip to the character before the closing brace */ while (cur > begin) { if (*cur == '>') break; --cur; } --cur; /* skip whitespace */ while (cur > begin && isspace(*cur)) cur--; if (*cur == '/') return NULL; /* we found a short tag which doesn't need to be closed */ while (cur > begin) { if (*cur == '<') break; /* exit immediately if such non-valid XML/HTML is detected, e.g. "