summaryrefslogtreecommitdiff
path: root/.gitignore
diff options
context:
space:
mode:
authorJonas Smedegaard <dr@jones.dk>2008-10-15 14:57:30 +0200
committerJonas Smedegaard <dr@jones.dk>2008-10-15 14:57:30 +0200
commitc6b99ac69908c3ae2ac2932f602f6e7a5a45084d (patch)
tree8a117480d121680838c2e7d7bd64e787d5e3b43c /.gitignore
parent3e09b44f0ba4509450d4edba971f1a8fcd6495fc (diff)
parent6159e285ef3745832000fb333349abf2fa56efe1 (diff)
Merge branch 'wian' into allinone-da
Diffstat (limited to '.gitignore')
0 files changed, 0 insertions, 0 deletions
nk *chunk, reference_map *refmap);
  • static void subject_from_buf(subject *e, strbuf *buffer, reference_map *refmap);
  • static int subject_find_special_char(subject *subj);
  • static unsigned char *bufdup(const unsigned char *buf)
  • {
  • unsigned char *new = NULL;
  • if (buf) {
  • int len = strlen((char *)buf);
  • new = calloc(len + 1, sizeof(*new));
  • if(new != NULL) {
  • memcpy(new, buf, len + 1);
  • }
  • }
  • return new;
  • }
  • static inline node_inl *make_link_(node_inl *label, unsigned char *url, unsigned char *title)
  • {
  • node_inl* e = calloc(1, sizeof(*e));
  • if(e != NULL) {
  • e->tag = INL_LINK;
  • e->content.linkable.label = label;
  • e->content.linkable.url = url;
  • e->content.linkable.title = title;
  • e->next = NULL;
  • }
  • return e;
  • }
  • inline static node_inl* make_ref_link(node_inl* label, reference *ref)
  • {
  • return make_link_(label, bufdup(ref->url), bufdup(ref->title));
  • }
  • inline static node_inl* make_autolink(node_inl* label, chunk url, int is_email)
  • {
  • return make_link_(label, clean_autolink(&url, is_email), NULL);
  • }
  • // Create an inline with a linkable string value.
  • inline static node_inl* make_link(node_inl* label, chunk url, chunk title)
  • {
  • return make_link_(label, clean_url(&url), clean_title(&title));
  • }
  • inline static node_inl* make_inlines(int t, node_inl* contents)
  • {
  • node_inl * e = calloc(1, sizeof(*e));
  • if(e != NULL) {
  • e->tag = t;
  • e->content.inlines = contents;
  • e->next = NULL;
  • }
  • return e;
  • }
  • // Create an inline with a literal string value.
  • inline static node_inl* make_literal(int t, chunk s)
  • {
  • node_inl * e = calloc(1, sizeof(*e));
  • if(e != NULL) {
  • e->tag = t;
  • e->content.literal = s;
  • e->next = NULL;
  • }
  • return e;
  • }
  • // Create an inline with no value.
  • inline static node_inl* make_simple(int t)
  • {
  • node_inl* e = calloc(1, sizeof(*e));
  • if(e != NULL) {
  • e->tag = t;
  • e->next = NULL;
  • }
  • return e;
  • }
  • // Macros for creating various kinds of inlines.
  • #define make_str(s) make_literal(INL_STRING, s)
  • #define make_code(s) make_literal(INL_CODE, s)
  • #define make_raw_html(s) make_literal(INL_RAW_HTML, s)
  • #define make_linebreak() make_simple(INL_LINEBREAK)
  • #define make_softbreak() make_simple(INL_SOFTBREAK)
  • #define make_emph(contents) make_inlines(INL_EMPH, contents)
  • #define make_strong(contents) make_inlines(INL_STRONG, contents)
  • // Utility function used by free_inlines
  • void splice_into_list(node_inl* e, node_inl* children) {
  • node_inl * tmp;
  • if (children) {
  • tmp = children;
  • // Find last child
  • while (tmp->next) {
  • tmp = tmp->next;
  • }
  • // Splice children into list
  • tmp->next = e->next;
  • e->next = children;
  • }
  • return ;
  • }
  • // Free an inline list. Avoid recursion to prevent stack overflows
  • // on deeply nested structures.
  • extern void free_inlines(node_inl* e)
  • {
  • node_inl * next;
  • while (e != NULL) {
  • switch (e->tag){
  • case INL_STRING:
  • case INL_RAW_HTML:
  • case INL_CODE:
  • chunk_free(&e->content.literal);
  • break;
  • case INL_LINEBREAK:
  • case INL_SOFTBREAK:
  • break;
  • case INL_LINK:
  • case INL_IMAGE:
  • free(e->content.linkable.url);
  • free(e->content.linkable.title);
  • splice_into_list(e, e->content.linkable.label);
  • break;
  • case INL_EMPH:
  • case INL_STRONG:
  • splice_into_list(e, e->content.inlines);
  • break;
  • default:
  • log_warn("Unknown inline tag %d", e->tag);
  • break;
  • }
  • next = e->next;
  • free(e);
  • e = next;
  • }
  • }
  • // Append inline list b to the end of inline list a.
  • // Return pointer to head of new list.
  • inline static node_inl* append_inlines(node_inl* a, node_inl* b)
  • {
  • if (a == NULL) { // NULL acts like an empty list
  • return b;
  • }
  • node_inl* cur = a;
  • while (cur->next) {
  • cur = cur->next;
  • }
  • cur->next = b;
  • return a;
  • }
  • static void subject_from_buf(subject *e, strbuf *buffer, reference_map *refmap)
  • {
  • e->input.data = buffer->ptr;
  • e->input.len = buffer->size;
  • e->input.alloc = 0;
  • e->pos = 0;
  • e->label_nestlevel = 0;
  • e->refmap = refmap;
  • e->emphasis_openers = NULL;
  • e->emphasis_nestlevel = 0;
  • chunk_rtrim(&e->input);
  • }
  • static void subject_from_chunk(subject *e, chunk *chunk, reference_map *refmap)
  • {
  • e->input.data = chunk->data;
  • e->input.len = chunk->len;
  • e->input.alloc = 0;
  • e->pos = 0;
  • e->label_nestlevel = 0;
  • e->refmap = refmap;
  • e->emphasis_openers = NULL;
  • e->emphasis_nestlevel = 0;
  • chunk_rtrim(&e->input);
  • }
  • inline static int isbacktick(int c)
  • {
  • return (c == '`');
  • }
  • static inline unsigned char peek_char(subject *subj)
  • {
  • return (subj->pos < subj->input.len) ? subj->input.data[subj->pos] : 0;
  • }
  • static inline unsigned char peek_at(subject *subj, int pos)
  • {
  • return subj->input.data[pos];
  • }
  • // Return true if there are more characters in the subject.
  • inline static int is_eof(subject* subj)
  • {
  • return (subj->pos >= subj->input.len);
  • }
  • // Advance the subject. Doesn't check for eof.
  • #define advance(subj) (subj)->pos += 1
  • // Take characters while a predicate holds, and return a string.
  • inline static chunk take_while(subject* subj, int (*f)(int))
  • {
  • unsigned char c;
  • int startpos = subj->pos;
  • int len = 0;
  • while ((c = peek_char(subj)) && (*f)(c)) {
  • advance(subj);
  • len++;
  • }
  • return chunk_dup(&subj->input, startpos, len);
  • }
  • // Try to process a backtick code span that began with a
  • // span of ticks of length openticklength length (already
  • // parsed). Return 0 if you don't find matching closing
  • // backticks, otherwise return the position in the subject
  • // after the closing backticks.
  • static int scan_to_closing_backticks(subject* subj, int openticklength)
  • {
  • // read non backticks
  • unsigned char c;
  • while ((c = peek_char(subj)) && c != '`') {
  • advance(subj);
  • }
  • if (is_eof(subj)) {
  • return 0; // did not find closing ticks, return 0
  • }
  • int numticks = 0;
  • while (peek_char(subj) == '`') {
  • advance(subj);
  • numticks++;
  • }
  • if (numticks != openticklength){
  • return(scan_to_closing_backticks(subj, openticklength));
  • }
  • return (subj->pos);
  • }
  • // Parse backtick code section or raw backticks, return an inline.
  • // Assumes that the subject has a backtick at the current position.
  • static node_inl* handle_backticks(subject *subj)
  • {
  • chunk openticks = take_while(subj, isbacktick);
  • int startpos = subj->pos;
  • int endpos = scan_to_closing_backticks(subj, openticks.len);
  • if (endpos == 0) { // not found
  • subj->pos = startpos; // rewind
  • return make_str(openticks);
  • } else {
  • strbuf buf = GH_BUF_INIT;
  • strbuf_set(&buf, subj->input.data + startpos, endpos - startpos - openticks.len);
  • strbuf_trim(&buf);
  • strbuf_normalize_whitespace(&buf);
  • return make_code(chunk_buf_detach(&buf));
  • }
  • }
  • // Scan ***, **, or * and return number scanned, or 0.
  • // Advances position.
  • static int scan_delims(subject* subj, unsigned char c, bool * can_open, bool * can_close)
  • {
  • int numdelims = 0;
  • unsigned char char_before, char_after;
  • char_before = subj->pos == 0 ? '\n' : peek_at(subj, subj->pos - 1);
  • while (peek_char(subj) == c) {
  • numdelims++;
  • advance(subj);
  • }
  • char_after = peek_char(subj);
  • *can_open = numdelims > 0 && !isspace(char_after);
  • *can_close = numdelims > 0 && !isspace(char_before);
  • if (c == '_') {
  • *can_open = *can_open && !isalnum(char_before);
  • *can_close = *can_close && !isalnum(char_after);
  • }
  • return numdelims;
  • }
  • static void free_openers(subject* subj, inline_stack* istack)
  • {
  • inline_stack * tempstack;
  • while (subj->emphasis_openers != istack) {
  • tempstack = subj->emphasis_openers;
  • subj->emphasis_openers = subj->emphasis_openers->previous;
  • subj->emphasis_nestlevel--;
  • free(tempstack);
  • }
  • }
  • // Parse strong/emph or a fallback.
  • // Assumes the subject has '_' or '*' at the current position.
  • static node_inl* handle_strong_emph(subject* subj, unsigned char c, node_inl **last)
  • {
  • bool can_open, can_close;
  • int numdelims;
  • int useDelims;
  • int openerDelims;
  • inline_stack * istack;
  • node_inl * inl;
  • node_inl * emph;
  • node_inl * inl_text;
  • numdelims = scan_delims(subj, c, &can_open, &can_close);
  • if (can_close)
  • {
  • // walk the stack and find a matching opener, if there is one
  • istack = subj->emphasis_openers;
  • while (true)
  • {
  • if (istack == NULL)
  • goto cannotClose;
  • if (istack->delim_char == c)
  • break;
  • istack = istack->previous;
  • }
  • // calculate the actual number of delimeters used from this closer
  • openerDelims = istack->delim_count;
  • if (numdelims < 3 || openerDelims < 3) {
  • useDelims = numdelims <= openerDelims ? numdelims : openerDelims;
  • } else { // (numdelims >= 3 && openerDelims >= 3)
  • useDelims = numdelims % 2 == 0 ? 2 : 1;
  • }
  • if (istack->delim_count == useDelims)
  • {
  • // the opener is completely used up - remove the stack entry and reuse the inline element
  • inl = istack->first_inline;
  • inl->tag = useDelims == 1 ? INL_EMPH : INL_STRONG;
  • chunk_free(&inl->content.literal);
  • inl->content.inlines = inl->next;
  • inl->next = NULL;
  • // remove this opener and all later ones from stack:
  • free_openers(subj, istack->previous);
  • *last = inl;
  • }
  • else
  • {
  • // the opener will only partially be used - stack entry remains (truncated) and a new inline is added.
  • inl = istack->first_inline;
  • istack->delim_count -= useDelims;
  • inl->content.literal.len = istack->delim_count;
  • emph = useDelims == 1 ? make_emph(inl->next) : make_strong(inl->next);
  • inl->next = emph;
  • // remove all later openers from stack:
  • free_openers(subj, istack);