/* bufnullterm: NULL-termination of the string array */ const char * bufcstr(struct buf *buf) { assert(buf && buf->unit); if (buf->size < buf->asize && buf->data[buf->size] == 0) return (char *)buf->data; if (buf->size + 1 <= buf->asize || bufgrow(buf, buf->size + 1) == 0) { buf->data[buf->size] = 0; return (char *)buf->data; } return NULL; }
void houdini_unescape_js(struct buf *ob, const uint8_t *src, size_t size) { size_t i = 0, org, ch; bufgrow(ob, UNESCAPE_GROW_FACTOR(size)); while (i < size) { org = i; while (i < size && src[i] != '\\') i++; if (i > org) bufput(ob, src + org, i - org); /* escaping */ if (i == size) break; if (++i == size) { bufputc(ob, '\\'); break; } ch = src[i]; switch (ch) { case 'n': ch = '\n'; /* pass through */ case '\\': case '\'': case '\"': case '/': bufputc(ob, ch); i++; break; default: bufputc(ob, '\\'); break; } } }
void houdini_unescape_html(struct buf *ob, const uint8_t *src, size_t size) { size_t i = 0, org; bufgrow(ob, UNESCAPE_GROW_FACTOR(size)); while (i < size) { org = i; while (i < size && src[i] != '&') i++; if (i > org) bufput(ob, src + org, i - org); /* escaping */ if (i >= size) break; i++; i += unescape_ent(ob, src + i, size - i); } }
/* bufnullterm • NUL-termination of the string array (making a C-string) */ void bufnullterm(struct buf *buf) { if (!buf || !buf->unit) return; if (buf->size < buf->asize && buf->data[buf->size] == 0) return; if (buf->size + 1 <= buf->asize || bufgrow(buf, buf->size + 1)) buf->data[buf->size] = 0; }
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; }
/* bufputc • appends a single char to a buffer */ void bufputc(struct buf *buf, char c) { if (!buf || !bufgrow(buf, buf->size + 1)) return; buf->data[buf->size] = c; buf->size += 1; }
/* bufput • appends raw data to a buffer */ void bufput(struct buf *buf, const void *data, size_t len) { if (!buf || !bufgrow(buf, buf->size + len)) return; memcpy(buf->data + buf->size, data, len); buf->size += len; }
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; }
void string_to_buf(struct buf *ib, const char *i) { bufgrow(ib, strlen(i)); ib->size = strlen(i); ib->data = strdup(i); }