aboutsummaryrefslogtreecommitdiffstats
path: root/lib/ephy-string.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/ephy-string.c')
-rw-r--r--lib/ephy-string.c446
1 files changed, 446 insertions, 0 deletions
diff --git a/lib/ephy-string.c b/lib/ephy-string.c
new file mode 100644
index 000000000..7ca28cf1f
--- /dev/null
+++ b/lib/ephy-string.c
@@ -0,0 +1,446 @@
+/*
+ * Copyright (C) 2002 Marco Pesenti Gritti
+ *
+ * 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, 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "ephy-string.h"
+
+#include <string.h>
+#include <glib.h>
+#include <libgnome/libgnome.h>
+#include <libgnome/gnome-i18n.h>
+#include <libgnomevfs/gnome-vfs-mime.h>
+#include <libxml/parser.h>
+
+/**
+ * ephy_string_shorten: returns a newly allocated shortened version of str.
+ * the new string will be no longer than target_length characters, and will
+ * be of the form "http://blahblah...blahblah.html".
+ */
+gchar *
+ephy_string_shorten (const gchar *str, gint target_length)
+{
+ gchar *new_str;
+ gint actual_length, first_length, second_length;
+
+ if (!str) return NULL;
+
+ actual_length = strlen (str);
+
+ /* if the string is already short enough, or if it's too short for
+ * us to shorten it, return a new copy */
+ if (actual_length <= target_length ||
+ actual_length <= 3)
+ return g_strdup (str);
+
+ /* allocate new string */
+ new_str = g_new (gchar, target_length + 1);
+
+ /* calc lengths to take from beginning and ending of str */
+ second_length = (target_length - 3) / 2;
+ first_length = target_length - 3 - second_length;
+
+ /* create string */
+ strncpy (new_str, str, first_length);
+ strncpy (new_str + first_length, "...", 3);
+ strncpy (new_str + first_length + 3,
+ str + actual_length - second_length, second_length);
+ new_str[target_length] = '\0';
+
+ return new_str;
+}
+
+char *
+ephy_string_double_underscores (const char *string)
+{
+ int underscores;
+ const char *p;
+ char *q;
+ char *escaped;
+
+ if (string == NULL) {
+ return NULL;
+ }
+
+ underscores = 0;
+ for (p = string; *p != '\0'; p++) {
+ underscores += (*p == '_');
+ }
+
+ if (underscores == 0) {
+ return g_strdup (string);
+ }
+
+ escaped = g_new (char, strlen (string) + underscores + 1);
+ for (p = string, q = escaped; *p != '\0'; p++, q++) {
+ /* Add an extra underscore. */
+ if (*p == '_') {
+ *q++ = '_';
+ }
+ *q = *p;
+ }
+ *q = '\0';
+
+ return escaped;
+}
+
+/**
+ * ephy_string_store_time_in_string:
+ * NOTE: str must be at least 256 chars long
+ */
+void
+ephy_string_store_time_in_string (GDate *t, gchar *str, const char *format)
+{
+ int length;
+
+ if (t > 0)
+ {
+ /* format into string */
+ /* this is used whenever a brief date is needed, like
+ * in the history (for last visited, first time visited) */
+ length = g_date_strftime (str, 255,
+ format ? format : _("%Y-%m-%d"), t);
+ str[length] = '\0';
+ }
+ else
+ {
+ str[0] = '\0';
+ }
+}
+
+/**
+ * ephy_string_time_to_string:
+ */
+gchar *
+ephy_string_time_to_string (GDate *t,
+ const char *format)
+{
+ gchar str[256];
+
+ /* write into stack string */
+ ephy_string_store_time_in_string (t, str, format);
+
+ /* copy in heap and return */
+ return g_strdup (str);
+}
+
+gboolean
+ephy_str_to_int (const char *string, int *integer)
+{
+ long result;
+ char *parse_end;
+
+ /* Check for the case of an empty string. */
+ if (string == NULL || *string == '\0') {
+ return FALSE;
+ }
+
+ /* Call the standard library routine to do the conversion. */
+ errno = 0;
+ result = strtol (string, &parse_end, 0);
+
+ /* Check that the result is in range. */
+ if ((result == G_MINLONG || result == G_MAXLONG) && errno == ERANGE) {
+ return FALSE;
+ }
+ if (result < G_MININT || result > G_MAXINT) {
+ return FALSE;
+ }
+
+ /* Check that all the trailing characters are spaces. */
+ while (*parse_end != '\0') {
+ if (!g_ascii_isspace (*parse_end++)) {
+ return FALSE;
+ }
+ }
+
+ /* Return the result. */
+ *integer = result;
+ return TRUE;
+}
+
+/**
+ * ephy_str_strip_chr:
+ * Remove all occurrences of a character from a string.
+ *
+ * @source: The string to be stripped.
+ * @remove_this: The char to remove from @source
+ *
+ * Return value: A copy of @source, after removing all occurrences
+ * of @remove_this.
+ */
+char *
+ephy_str_strip_chr (const char *source, char remove_this)
+{
+ char *result, *out;
+ const char *in;
+
+ if (source == NULL) {
+ return NULL;
+ }
+
+ result = g_new (char, strlen (source) + 1);
+ in = source;
+ out = result;
+ do {
+ if (*in != remove_this) {
+ *out++ = *in;
+ }
+ } while (*in++ != '\0');
+
+ return result;
+}
+
+int
+ephy_strcasecmp (const char *string_a, const char *string_b)
+{
+ return g_ascii_strcasecmp (string_a == NULL ? "" : string_a,
+ string_b == NULL ? "" : string_b);
+}
+
+int
+ephy_strcasecmp_compare_func (gconstpointer string_a, gconstpointer string_b)
+{
+ return ephy_strcasecmp ((const char *) string_a,
+ (const char *) string_b);
+}
+
+/**
+ * like strpbrk but ignores chars preceded by slashes, unless the
+ * slash is also preceded by a slash unless that later slash is
+ * preceded by another slash... ;-)
+ */
+static char *
+ephy_strpbrk_unescaped (const char *s, const char *accept)
+{
+ gchar *ret = strpbrk (s, accept);
+
+ if (!ret || ret == s || *(ret - 1) != '\\')
+ {
+ return ret;
+ }
+ else
+ {
+ gchar *c = ret - 1;
+ g_assert (*c == '\\');
+
+ while (c >= s && *c == '\\') c--;
+
+ if ((ret - c) % 2 == 0)
+ {
+ return ephy_strpbrk_unescaped (ret + 1, accept);
+ }
+ else
+ {
+ return ret;
+ }
+ }
+}
+
+/**
+ * like strstr but supports quoting, ignoring matches inside quoted text
+ */
+static char *
+ephy_strstr_with_quotes (const char *haystack, const char *needle,
+ const char *quotes)
+{
+ gchar *quot = ephy_strpbrk_unescaped (haystack, quotes);
+ gchar *ret = strstr (haystack, needle);
+
+ if (!quot || !ret || ret < quot)
+ {
+ return ret;
+ }
+
+ quot = ephy_strpbrk_unescaped (quot + 1, quotes);
+
+ if (quot)
+ {
+ return ephy_strstr_with_quotes (quot + 1, needle, quotes);
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+/**
+ * like strpbrk but supports quoting, ignoring matches inside quoted text
+ */
+static char *
+ephy_strpbrk_with_quotes (const char *haystack, const char *needles,
+ const char *quotes)
+{
+ gchar *quot = ephy_strpbrk_unescaped (haystack, quotes);
+ gchar *ret = strpbrk (haystack, needles);
+
+ if (!quot || !ret || ret < quot)
+ {
+ return ret;
+ }
+
+ quot = ephy_strpbrk_unescaped (quot + 1, quotes);
+
+ if (quot)
+ {
+ return ephy_strpbrk_with_quotes (quot + 1, needles, quotes);
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+/**
+ * Like g_strsplit, but does not split tokens betwen quotes. Ignores
+ * quotes preceded by '\'.
+ */
+gchar **
+ephy_strsplit_with_quotes (const gchar *string,
+ const gchar *delimiter,
+ gint max_tokens,
+ const gchar *quotes)
+{
+ GSList *string_list = NULL, *slist;
+ gchar **str_array, *s;
+ guint n = 0;
+ const gchar *remainder;
+
+ g_return_val_if_fail (string != NULL, NULL);
+ g_return_val_if_fail (delimiter != NULL, NULL);
+ g_return_val_if_fail (delimiter[0] != '\0', NULL);
+
+ if (quotes == NULL)
+ {
+ return g_strsplit (string, delimiter, max_tokens);
+ }
+
+ if (max_tokens < 1)
+ {
+ max_tokens = G_MAXINT;
+ }
+
+ remainder = string;
+ s = ephy_strstr_with_quotes (remainder, delimiter, quotes);
+ if (s)
+ {
+ gsize delimiter_len = strlen (delimiter);
+
+ while (--max_tokens && s)
+ {
+ gsize len;
+ gchar *new_string;
+
+ len = s - remainder;
+ new_string = g_new (gchar, len + 1);
+ strncpy (new_string, remainder, len);
+ new_string[len] = 0;
+ string_list = g_slist_prepend (string_list, new_string);
+ n++;
+ remainder = s + delimiter_len;
+ s = ephy_strstr_with_quotes (remainder, delimiter, quotes);
+ }
+ }
+ if (*string)
+ {
+ n++;
+ string_list = g_slist_prepend (string_list, g_strdup (remainder));
+ }
+
+ str_array = g_new (gchar*, n + 1);
+
+ str_array[n--] = NULL;
+ for (slist = string_list; slist; slist = slist->next)
+ {
+ str_array[n--] = slist->data;
+ }
+
+ g_slist_free (string_list);
+
+ return str_array;
+}
+
+/**
+ * like ephy_strsplit_with_quotes, but matches any char in 'delimiters' as delimiter
+ * and does not return empty tokens
+ */
+gchar **
+ephy_strsplit_multiple_delimiters_with_quotes (const gchar *string,
+ const gchar *delimiters,
+ gint max_tokens,
+ const gchar *quotes)
+{
+ GSList *string_list = NULL, *slist;
+ gchar **str_array, *s;
+ guint n = 0;
+ const gchar *remainder;
+
+ g_return_val_if_fail (string != NULL, NULL);
+ g_return_val_if_fail (delimiters != NULL, NULL);
+ g_return_val_if_fail (delimiters[0] != '\0', NULL);
+
+ if (quotes == NULL)
+ {
+ quotes = "";
+ }
+
+ if (max_tokens < 1)
+ {
+ max_tokens = G_MAXINT;
+ }
+
+ remainder = string;
+ s = ephy_strpbrk_with_quotes (remainder, delimiters, quotes);
+ if (s)
+ {
+ const gsize delimiter_len = 1; /* only chars */
+
+ while (--max_tokens && s)
+ {
+ gsize len;
+ gchar *new_string;
+
+ len = s - remainder;
+ if (len > 0) /* ignore empty strings */
+ {
+ new_string = g_new (gchar, len + 1);
+ strncpy (new_string, remainder, len);
+ new_string[len] = 0;
+ string_list = g_slist_prepend (string_list, new_string);
+ n++;
+ }
+ remainder = s + delimiter_len;
+ s = ephy_strpbrk_with_quotes (remainder, delimiters, quotes);
+ }
+ }
+ if (*string)
+ {
+ n++;
+ string_list = g_slist_prepend (string_list, g_strdup (remainder));
+ }
+
+ str_array = g_new (gchar*, n + 1);
+
+ str_array[n--] = NULL;
+ for (slist = string_list; slist; slist = slist->next)
+ {
+ str_array[n--] = slist->data;
+ }
+
+ g_slist_free (string_list);
+
+ return str_array;
+}