int rinku_autolink( struct buf *ob, const uint8_t *text, size_t size, autolink_mode mode, unsigned int flags, const char *link_attr, const char **skip_tags, void (*link_text_cb)(struct buf *ob, const struct buf *link, void *payload), void *payload) { size_t i, end, last_link_found = 0; struct buf *link = bufnew(16); char active_chars[256]; void (*link_url_cb)(struct buf *, const struct buf *, void *); int link_count = 0; if (!text || size == 0) return 0; memset(active_chars, 0x0, sizeof(active_chars)); active_chars['<'] = AUTOLINK_ACTION_SKIP_TAG; if (mode & AUTOLINK_EMAILS) active_chars['@'] = AUTOLINK_ACTION_EMAIL; if (mode & AUTOLINK_URLS) { active_chars['w'] = AUTOLINK_ACTION_WWW; active_chars['W'] = AUTOLINK_ACTION_WWW; active_chars[':'] = AUTOLINK_ACTION_URL; } if (link_text_cb == NULL) link_text_cb = &autolink__print; if (link_attr != NULL) { while (isspace(*link_attr)) link_attr++; } bufgrow(ob, size); i = end = 0; while (i < size) { size_t rewind, link_end; char action = 0; while (end < size && (action = active_chars[text[end]]) == 0) end++; if (end == size) { if (link_count > 0) bufput(ob, text + i, end - i); break; } if (action == AUTOLINK_ACTION_SKIP_TAG) { end += autolink__skip_tag(ob, text + end, size - end, skip_tags); continue; } link->size = 0; link_end = g_callbacks[(int)action]( &rewind, link, (uint8_t *)text + end, end - last_link_found, size - end, flags); /* print the link */ if (link_end > 0) { bufput(ob, text + i, end - i - rewind); bufputs(ob, g_hrefs[(int)action]); print_link(ob, link->data, link->size); if (link_attr) { BUFPUTSL(ob, "\" "); bufputs(ob, link_attr); bufputc(ob, '>'); } else { BUFPUTSL(ob, "\">"); } link_text_cb(ob, link, payload); BUFPUTSL(ob, "</a>"); link_count++; i = end + link_end; last_link_found = end = i; } else { end = end + 1; } } bufrelease(link); return link_count; }
int rinku_autolink( struct buf *ob, const uint8_t *text, size_t size, autolink_mode mode, unsigned int flags, const char *link_attr, const char **skip_tags, void (*link_text_cb)(struct buf *, const uint8_t *, size_t, void *), void *payload) { size_t i, end; char active_chars[256] = {0}; int link_count = 0; if (!text || size == 0) return 0; active_chars['<'] = AUTOLINK_ACTION_SKIP_TAG; if (mode & AUTOLINK_EMAILS) active_chars['@'] = AUTOLINK_ACTION_EMAIL; if (mode & AUTOLINK_URLS) { active_chars['w'] = AUTOLINK_ACTION_WWW; active_chars['W'] = AUTOLINK_ACTION_WWW; active_chars[':'] = AUTOLINK_ACTION_URL; } if (link_attr != NULL) { while (rinku_isspace(*link_attr)) link_attr++; } bufgrow(ob, size); i = end = 0; while (i < size) { struct autolink_pos link; bool link_found; char action = 0; while (end < size && (action = active_chars[text[end]]) == 0) end++; if (end == size) { if (link_count > 0) bufput(ob, text + i, end - i); break; } if (action == AUTOLINK_ACTION_SKIP_TAG) { end += autolink__skip_tag(ob, text + end, size - end, skip_tags); continue; } link_found = g_callbacks[(int)action]( &link, text, end, size, flags); if (link_found && link.start >= i) { const uint8_t *link_str = text + link.start; const size_t link_len = link.end - link.start; bufput(ob, text + i, link.start - i); bufputs(ob, g_hrefs[(int)action]); print_link(ob, link_str, link_len); if (link_attr) { BUFPUTSL(ob, "\" "); bufputs(ob, link_attr); bufputc(ob, '>'); } else { BUFPUTSL(ob, "\">"); } if (link_text_cb) { link_text_cb(ob, link_str, link_len, payload); } else { bufput(ob, link_str, link_len); } BUFPUTSL(ob, "</a>"); link_count++; end = i = link.end; } else { end = end + 1; } } return link_count; }