autolinking: fix bugs

This commit is contained in:
Vicent Marti 2011-06-08 23:11:58 +02:00
parent cbb7fb53c6
commit 8af37fd1b4
3 changed files with 99 additions and 100 deletions

View file

@ -70,13 +70,18 @@ skip_tags(struct buf *ob, const char *text, size_t size)
}
bufput(ob, text, i + 1);
return i;
return i + 1;
}
void
upshtml_autolink(struct buf *ob, struct buf *text, unsigned int flags)
upshtml_autolink(
struct buf *ob,
struct buf *text,
unsigned int flags,
void (*link_text_cb)(struct buf *ob, const struct buf *link, void *payload),
void *payload)
{
size_t i;
size_t i, end;
struct buf *link = bufnew(16);
const char *active_chars;
@ -101,72 +106,76 @@ upshtml_autolink(struct buf *ob, struct buf *text, unsigned int flags)
bufgrow(ob, text->size);
for (i = 0; i < text->size; ++i) {
size_t org, rewind, link_size;
i = end = 0;
org = i;
while (i < text->size && strchr(active_chars, text->data[i]) == NULL)
i++;
while (i < text->size) {
size_t rewind;
if (i > org)
bufput(ob, text->data + org, i - org);
while (end < text->size && strchr(active_chars, text->data[end]) == NULL)
end++;
if (i == text->size)
bufput(ob, text->data + i, end - i);
if (end >= text->size)
break;
i = end;
link->size = 0;
switch (text->data[i]) {
case '@':
link_size = ups_autolink__email(&rewind, link, text->data + i, i, text->size - i);
if (link_size == 0)
break;
ob->size -= rewind;
BUFPUTSL(ob, "<a href=\"mailto:");
bufput(ob, link->data, link->size);
BUFPUTSL(ob, "\">");
upshtml_escape(ob, link->data, link->size);
BUFPUTSL(ob, "</a>");
i += link_size;
continue;
end = ups_autolink__email(&rewind, link, text->data + i, i, text->size - i);
if (end > 0) {
ob->size -= rewind;
BUFPUTSL(ob, "<a href=\"mailto:");
bufput(ob, link->data, link->size);
BUFPUTSL(ob, "\">");
if (link_text_cb) callback(ob, link, payload);
else upshtml_escape(ob, link->data, link->size);
BUFPUTSL(ob, "</a>");
}
break;
case 'w':
link_size = ups_autolink__www(&rewind, link, text->data + i, i, text->size - i);
if (link_size == 0)
break;
BUFPUTSL(ob, "<a href=\"http://");
bufput(ob, link->data, link->size);
BUFPUTSL(ob, "\">");
upshtml_escape(ob, link->data, link->size);
BUFPUTSL(ob, "</a>");
i += link_size;
continue;
end = ups_autolink__www(&rewind, link, text->data + i, i, text->size - i);
if (end > 0) {
BUFPUTSL(ob, "<a href=\"http://");
bufput(ob, link->data, link->size);
BUFPUTSL(ob, "\">");
if (link_text_cb) callback(ob, link, payload);
else upshtml_escape(ob, link->data, link->size);
BUFPUTSL(ob, "</a>");
}
break;
case ':':
link_size = ups_autolink__url(&rewind, link, text->data + i, i, text->size - i);
if (link_size == 0)
break;
ob->size -= rewind;
BUFPUTSL(ob, "<a href=\"");
bufput(ob, link->data, link->size);
BUFPUTSL(ob, "\">");
upshtml_escape(ob, link->data, link->size);
BUFPUTSL(ob, "</a>");
i += link_size;
continue;
end = ups_autolink__url(&rewind, link, text->data + i, i, text->size - i);
if (end > 0) {
ob->size -= rewind;
BUFPUTSL(ob, "<a href=\"");
bufput(ob, link->data, link->size);
BUFPUTSL(ob, "\">");
if (link_text_cb) callback(ob, link, payload);
else upshtml_escape(ob, link->data, link->size);
BUFPUTSL(ob, "</a>");
}
break;
case '<':
i += skip_tags(ob, text->data + i, text->size - i);
continue;
end = skip_tags(ob, text->data + i, text->size - i);
break;
default:
end = 0;
break;
}
bufputc(ob, text->data[i]);
if (!end)
end = i + 1;
else {
i += end;
end = i;
}
}
}

View file

@ -49,36 +49,32 @@ autolink_delim(char *data, size_t link_end, size_t offset, size_t size)
{
char cclose, copen = 0;
/* See if the link finishes with a punctuation sign that can be skipped. */
switch (data[link_end - 1]) {
case '?':
case '!':
case '.':
case ',':
link_end--;
break;
}
if (data[link_end - 1] == ';') {
size_t new_end = link_end - 2;
while (new_end > 0 && isalpha(data[new_end]))
new_end--;
if (new_end < link_end - 2 && data[new_end] == '&')
link_end = new_end;
else
link_end--;
}
if (data[link_end - 1] == '>') {
while (link_end > 0 && data[link_end] != '<')
while (link_end > 0) {
if (strchr("?!.,", data[link_end - 1]) != NULL)
link_end--;
if (link_end == 0)
return 0;
else if (data[link_end - 1] == ';') {
size_t new_end = link_end - 2;
while (new_end > 0 && isalpha(data[new_end]))
new_end--;
if (new_end < link_end - 2 && data[new_end] == '&')
link_end = new_end;
else
link_end--;
}
else if (data[link_end - 1] == '>') {
while (link_end > 0 && data[link_end] != '<')
link_end--;
}
else break;
}
if (link_end == 0)
return 0;
cclose = data[link_end - 1];
switch (cclose) {

View file

@ -719,19 +719,17 @@ char_autolink_www(struct buf *ob, struct render *rndr, char *data, size_t offset
link = rndr_newbuf(rndr, BUFFER_SPAN);
if ((link_len = ups_autolink__www(&rewind, link, data, offset, size)) == 0)
return 0;
if ((link_len = ups_autolink__www(&rewind, link, data, offset, size)) > 0) {
link_url = rndr_newbuf(rndr, BUFFER_SPAN);
BUFPUTSL(link_url, "http://");
bufput(link_url, link->data, link->size);
link_url = rndr_newbuf(rndr, BUFFER_SPAN);
BUFPUTSL(link_url, "http://");
bufput(link_url, link->data, link->size);
ob->size -= rewind;
rndr->make.link(ob, link_url, NULL, link, rndr->make.opaque);
ob->size -= rewind;
rndr->make.link(ob, link_url, NULL, link, rndr->make.opaque);
rndr_popbuf(rndr, BUFFER_SPAN);
}
rndr_popbuf(rndr, BUFFER_SPAN);
rndr_popbuf(rndr, BUFFER_SPAN);
return link_len;
}
@ -746,14 +744,12 @@ char_autolink_email(struct buf *ob, struct render *rndr, char *data, size_t offs
link = rndr_newbuf(rndr, BUFFER_SPAN);
if ((link_len = ups_autolink__email(&rewind, link, data, offset, size)) == 0)
return 0;
ob->size -= rewind;
rndr->make.autolink(ob, link, MKDA_EMAIL, rndr->make.opaque);
if ((link_len = ups_autolink__email(&rewind, link, data, offset, size)) > 0) {
ob->size -= rewind;
rndr->make.autolink(ob, link, MKDA_EMAIL, rndr->make.opaque);
}
rndr_popbuf(rndr, BUFFER_SPAN);
return link_len;
}
@ -768,14 +764,12 @@ char_autolink_url(struct buf *ob, struct render *rndr, char *data, size_t offset
link = rndr_newbuf(rndr, BUFFER_SPAN);
if ((link_len = ups_autolink__url(&rewind, link, data, offset, size)) == 0)
return 0;
ob->size -= rewind;
rndr->make.autolink(ob, link, MKDA_NORMAL, rndr->make.opaque);
if ((link_len = ups_autolink__url(&rewind, link, data, offset, size)) > 0) {
ob->size -= rewind;
rndr->make.autolink(ob, link, MKDA_NORMAL, rndr->make.opaque);
}
rndr_popbuf(rndr, BUFFER_SPAN);
return link_len;
}