2012-10-25 [colin] 3.8.1cvs107
[claws.git] / src / textview.c
index d91b3ff1f72ae8481382f92f05e508dfbe148635..b47a8813812efec3eec64e3234d9100f0a20ac6a 100644 (file)
@@ -1311,7 +1311,8 @@ static void textview_make_clickable_parts(TextView *textview,
        GtkTextView *text = GTK_TEXT_VIEW(textview->text);
        GtkTextBuffer *buffer = gtk_text_view_get_buffer(text);
        GtkTextIter iter;
-       gchar *mybuf = g_strdup(linebuf);
+       gint mybuf_len = strlen(linebuf);
+       gchar *mybuf = g_strndup(linebuf, mybuf_len);
        
        /* parse table - in order of priority */
        struct table {
@@ -1319,6 +1320,7 @@ static void textview_make_clickable_parts(TextView *textview,
 
                /* token search function */
                gchar    *(*search)     (const gchar *haystack,
+                                        gint  haystack_len,
                                         const gchar *needle);
                /* part parsing function */
                gboolean  (*parse)      (const gchar *start,
@@ -1332,14 +1334,14 @@ static void textview_make_clickable_parts(TextView *textview,
        };
 
        static struct table parser[] = {
-               {"http://",  strcasestr, get_uri_part,   make_uri_string},
-               {"https://", strcasestr, get_uri_part,   make_uri_string},
-               {"ftp://",   strcasestr, get_uri_part,   make_uri_string},
-               {"sftp://",  strcasestr, get_uri_part,   make_uri_string},
-               {"gopher://",strcasestr, get_uri_part,   make_uri_string},
-               {"www.",     strcasestr, get_uri_part,   make_http_string},
-               {"mailto:",  strcasestr, get_uri_part,   make_uri_string},
-               {"@",        strcasestr, get_email_part, make_email_string}
+               {"http://",  strncasestr, get_uri_part,   make_uri_string},
+               {"https://", strncasestr, get_uri_part,   make_uri_string},
+               {"ftp://",   strncasestr, get_uri_part,   make_uri_string},
+               {"sftp://",  strncasestr, get_uri_part,   make_uri_string},
+               {"gopher://",strncasestr, get_uri_part,   make_uri_string},
+               {"www.",     strncasestr, get_uri_part,   make_http_string},
+               {"mailto:",  strncasestr, get_uri_part,   make_uri_string},
+               {"@",        strncasestr, get_email_part, make_email_string}
        };
        const gint PARSE_ELEMS = sizeof parser / sizeof parser[0];
 
@@ -1354,51 +1356,50 @@ static void textview_make_clickable_parts(TextView *textview,
 
        if (!g_utf8_validate(linebuf, -1, NULL)) {
                g_free(mybuf);
-               mybuf = g_malloc(strlen(linebuf)*2 +1);
-               conv_localetodisp(mybuf, strlen(linebuf)*2 +1, linebuf);
+               mybuf = g_malloc(mybuf_len*2 +1);
+               conv_localetodisp(mybuf, mybuf_len*2 +1, linebuf);
+               mybuf_len = strlen(mybuf);
        }
 
        gtk_text_buffer_get_end_iter(buffer, &iter);
 
        /* parse for clickable parts, and build a list of begin and end positions  */
-       for (walk = mybuf;;) {
-               gint last_index = PARSE_ELEMS;
-               gchar *scanpos = NULL;
-
-               /* FIXME: this looks phony. scanning for anything in the parse table */
-               for (n = 0; n < PARSE_ELEMS; n++) {
-                       gchar *tmp;
-
-                       tmp = parser[n].search(walk, parser[n].needle);
-                       if (tmp) {
-                               if (scanpos == NULL || tmp < scanpos) {
-                                       scanpos = tmp;
-                                       last_index = n;
-                               }
-                       }                                       
-               }
-
-               if (scanpos) {
-                       /* check if URI can be parsed */
-                       if (parser[last_index].parse(walk, scanpos, &bp, &ep, hdr)
-                           && (size_t) (ep - bp - 1) > strlen(parser[last_index].needle)) {
-                                       ADD_TXT_POS(bp, ep, last_index);
+       for (n = 0; n < PARSE_ELEMS; n++) {
+               gint len = mybuf_len;
+               gint needle_len = strlen(parser[n].needle);
+               for (walk = mybuf;;) {
+                       gchar *scanpos = parser[n].search(walk, len, parser[n].needle);
+                       if (scanpos) {
+                               /* check if URI can be parsed */
+                               if (parser[n].parse(walk, scanpos, &bp, &ep, hdr)
+                                               && (size_t) (ep - bp - 1) > needle_len) {
+                                       ADD_TXT_POS(bp, ep, n);
+                                       len -= ep - walk;
                                        walk = ep;
+                               } else {
+                                       len -= (scanpos + needle_len) - walk;
+                                       walk = scanpos + needle_len;
+                               }
                        } else
-                               walk = scanpos +
-                                       strlen(parser[last_index].needle);
-               } else
-                       break;
+                               break;
+               }
        }
 
        /* colorize this line */
        if (head.next) {
                const gchar *normal_text = mybuf;
+               struct txtpos *previous = NULL;
 
                /* insert URIs */
                for (last = head.next; last != NULL;
                     normal_text = last->ep, last = last->next) {
                        ClickableText *uri;
+
+                       if (previous != NULL
+                           && previous->bp < last->bp 
+                           && previous->ep == last->ep)
+                               continue;
+
                        uri = g_new0(ClickableText, 1);
                        if (last->bp - normal_text > 0)
                                gtk_text_buffer_insert_with_tags_by_name
@@ -1416,6 +1417,7 @@ static void textview_make_clickable_parts(TextView *textview,
                        uri->filename = NULL;
                        textview->uri_list =
                                g_slist_prepend(textview->uri_list, uri);
+                       previous = last;
                }
 
                if (*normal_text)
@@ -1436,6 +1438,7 @@ static void textview_make_clickable_parts_later(TextView *textview,
        GtkTextBuffer *buffer = gtk_text_view_get_buffer(text);
        GtkTextIter start_iter, end_iter;
        gchar *mybuf;
+       gint mybuf_len;
        gint offset = 0;
        /* parse table - in order of priority */
        struct table {
@@ -1443,6 +1446,7 @@ static void textview_make_clickable_parts_later(TextView *textview,
 
                /* token search function */
                gchar    *(*search)     (const gchar *haystack,
+                                        gint  haystack_len,
                                         const gchar *needle);
                /* part parsing function */
                gboolean  (*parse)      (const gchar *start,
@@ -1456,13 +1460,13 @@ static void textview_make_clickable_parts_later(TextView *textview,
        };
 
        static struct table parser[] = {
-               {"http://",  strcasestr, get_uri_part,   make_uri_string},
-               {"https://", strcasestr, get_uri_part,   make_uri_string},
-               {"ftp://",   strcasestr, get_uri_part,   make_uri_string},
-               {"sftp://",  strcasestr, get_uri_part,   make_uri_string},
-               {"www.",     strcasestr, get_uri_part,   make_http_string},
-               {"mailto:",  strcasestr, get_uri_part,   make_uri_string},
-               {"@",        strcasestr, get_email_part, make_email_string}
+               {"http://",  strncasestr, get_uri_part,   make_uri_string},
+               {"https://", strncasestr, get_uri_part,   make_uri_string},
+               {"ftp://",   strncasestr, get_uri_part,   make_uri_string},
+               {"sftp://",  strncasestr, get_uri_part,   make_uri_string},
+               {"www.",     strncasestr, get_uri_part,   make_http_string},
+               {"mailto:",  strncasestr, get_uri_part,   make_uri_string},
+               {"@",        strncasestr, get_email_part, make_email_string}
        };
        const gint PARSE_ELEMS = sizeof parser / sizeof parser[0];
 
@@ -1481,44 +1485,43 @@ static void textview_make_clickable_parts_later(TextView *textview,
        offset = gtk_text_iter_get_offset(&start_iter);
 
        /* parse for clickable parts, and build a list of begin and end positions  */
-       for (walk = mybuf;;) {
-               gint last_index = PARSE_ELEMS;
-               gchar *scanpos = NULL;
-
-               /* FIXME: this looks phony. scanning for anything in the parse table */
-               for (n = 0; n < PARSE_ELEMS; n++) {
-                       gchar *tmp;
-
-                       tmp = parser[n].search(walk, parser[n].needle);
-                       if (tmp) {
-                               if (scanpos == NULL || tmp < scanpos) {
-                                       scanpos = tmp;
-                                       last_index = n;
-                               }
-                       }                                       
-               }
-
-               if (scanpos) {
-                       /* check if URI can be parsed */
-                       if (parser[last_index].parse(walk, scanpos, &bp, &ep, FALSE)
-                           && (size_t) (ep - bp - 1) > strlen(parser[last_index].needle)) {
-                                       ADD_TXT_POS_LATER(bp, ep, last_index);
+       mybuf_len = strlen(mybuf);
+       for (n = 0; n < PARSE_ELEMS; n++) {
+               gint len = mybuf_len;
+               gint needle_len = strlen(parser[n].needle);
+               for (walk = mybuf;;) {
+                       gchar *scanpos = parser[n].search(walk, len, parser[n].needle);
+                       if (scanpos) {
+                               /* check if URI can be parsed */
+                               if (parser[n].parse(walk, scanpos, &bp, &ep, FALSE)
+                                               && (size_t) (ep - bp - 1) > needle_len) {
+                                       ADD_TXT_POS_LATER(bp, ep, n);
+                                       len -= ep - walk;
                                        walk = ep;
+                               } else {
+                                       len -= (scanpos + needle_len) - walk;
+                                       walk = scanpos + needle_len;
+                               }
                        } else
-                               walk = scanpos +
-                                       strlen(parser[last_index].needle);
-               } else
-                       break;
+                               break;
+               }
        }
 
        /* colorize this line */
        if (head.next) {
+               struct txtpos *previous = NULL;
                /* insert URIs */
                for (last = head.next; last != NULL; last = last->next) {
                        ClickableText *uri;
                        gint start_offset, end_offset;
                        gchar *tmp_str;
                        gchar old_char;
+
+                       if (previous != NULL
+                           && previous->bp < last->bp 
+                           && previous->ep == last->ep)
+                               continue;
+
                        uri = g_new0(ClickableText, 1);
                        uri->uri = parser[last->pti].build_uri(last->bp,
                                                               last->ep);
@@ -1545,6 +1548,7 @@ static void textview_make_clickable_parts_later(TextView *textview,
                        uri->filename = NULL;
                        textview->uri_list =
                                g_slist_prepend(textview->uri_list, uri);
+                       previous = last;
                }
        } 
 
@@ -1637,6 +1641,7 @@ do_quote:
                        uri = g_new0(ClickableText, 1);
                        uri->uri = g_strdup("");
                        uri->data = g_strdup(buf);
+                       uri->data_len = strlen(uri->data);
                        uri->start = gtk_text_iter_get_offset(&iter);
                        uri->is_quote = TRUE;
                        uri->quote_level = real_quotelevel;
@@ -1669,11 +1674,12 @@ do_quote:
                                        textview->prev_quote_level = -1;
                                        goto do_quote;
                                }
-                               e_len = lasturi->data ? strlen(lasturi->data):0;
+                               e_len = lasturi->data ? lasturi->data_len:0;
                                n_len = strlen(buf);
                                lasturi->data = g_realloc((gchar *)lasturi->data, e_len + n_len + 1);
                                strcpy((gchar *)lasturi->data + e_len, buf);
                                *((gchar *)lasturi->data + e_len + n_len) = '\0';
+                               lasturi->data_len += n_len;
                        }
                }
        } else {