static delimiter *S_insert_emph(subject *subj, delimiter *opener, delimiter *closer) { delimiter *delim, *tmp_delim; bufsize_t use_delims; cmark_node *opener_inl = opener->inl_text; cmark_node *closer_inl = closer->inl_text; bufsize_t opener_num_chars = opener_inl->as.literal.len; bufsize_t closer_num_chars = closer_inl->as.literal.len; cmark_node *tmp, *tmpnext, *emph; // calculate the actual number of characters used from this closer use_delims = (closer_num_chars >= 2 && opener_num_chars >=2) ? 2 : 1; // remove used characters from associated inlines. opener_num_chars -= use_delims; closer_num_chars -= use_delims; opener_inl->as.literal.len = opener_num_chars; closer_inl->as.literal.len = closer_num_chars; // free delimiters between opener and closer delim = closer->previous; while (delim != NULL && delim != opener) { tmp_delim = delim->previous; remove_delimiter(subj, delim); delim = tmp_delim; } // create new emph or strong, and splice it in to our inlines // between the opener and closer emph = use_delims == 1 ? make_emph(subj->mem) : make_strong(subj->mem); tmp = opener_inl->next; while (tmp && tmp != closer_inl) { tmpnext = tmp->next; cmark_node_append_child(emph, tmp); tmp = tmpnext; } cmark_node_insert_after(opener_inl, emph); // if opener has 0 characters, remove it and its associated inline if (opener_num_chars == 0) { cmark_node_free(opener_inl); remove_delimiter(subj, opener); } // if closer has 0 characters, remove it and its associated inline if (closer_num_chars == 0) { // remove empty closer inline cmark_node_free(closer_inl); // remove closer from list tmp_delim = closer->next; remove_delimiter(subj, closer); closer = tmp_delim; } return closer; }
static void process_emphasis(subject *subj, delimiter *start_delim) { delimiter *closer = subj->last_delim; delimiter *opener; // move back to first relevant delim. while (closer != NULL && closer->previous != start_delim) { closer = closer->previous; } // now move forward, looking for closers, and handling each while (closer != NULL) { if (closer->can_close && (closer->delim_char == '*' || closer->delim_char == '_' || closer->delim_char == '"' || closer->delim_char == '\'')) { // Now look backwards for first matching opener: opener = closer->previous; while (opener != NULL && opener != start_delim) { if (opener->delim_char == closer->delim_char && opener->can_open) { break; } opener = opener->previous; } if (closer->delim_char == '*' || closer->delim_char == '_') { if (opener != NULL && opener != start_delim) { closer = S_insert_emph(subj, opener, closer); } else { closer = closer->next; } } else if (closer->delim_char == '\'') { cmark_chunk_free(&closer->inl_text->as.literal); closer->inl_text->as.literal = cmark_chunk_literal(RIGHTSINGLEQUOTE); if (opener != NULL && opener != start_delim) { cmark_chunk_free(&opener->inl_text->as.literal); opener->inl_text->as.literal = cmark_chunk_literal(LEFTSINGLEQUOTE); } closer = closer->next; } else if (closer->delim_char == '"') { cmark_chunk_free(&closer->inl_text->as.literal); closer->inl_text->as.literal = cmark_chunk_literal(RIGHTDOUBLEQUOTE); if (opener != NULL && opener != start_delim) { cmark_chunk_free(&opener->inl_text->as.literal); opener->inl_text->as.literal = cmark_chunk_literal(LEFTDOUBLEQUOTE); } closer = closer->next; } } else { closer = closer->next; } } // free all delimiters in list until start_delim: while (subj->last_delim != start_delim) { remove_delimiter(subj, subj->last_delim); } }
/* * Parse a mapping table and create the appropriate targets or * check that a target type is registered with the device-mapper core. */ static int handle_table(struct lib_context *lc, struct dm_task *dmt, char *table, struct dm_versions *targets) { int line = 0, n, ret = 0; uint64_t start, size; char *nl = table, *p, ttype[32]; do { p = nl; line++; /* * Not using sscanf string allocation * because it's not available in dietlibc. */ *ttype = 0; if (sscanf(p, "%" PRIu64 " %" PRIu64 " %31s %n", &start, &size, ttype, &n) < 3) LOG_ERR(lc, 0, "Invalid format in table line %d", line); if (!(ret = valid_ttype(lc, ttype, targets))) break; nl = remove_delimiter((p += n), '\n'); if (dmt) ret = dm_task_add_target(dmt, start, size, ttype, p); add_delimiter(&nl, '\n'); } while (nl && ret); return ret; }
// Parse inlines from parent's string_content, adding as children of parent. extern void cmark_parse_inlines(cmark_mem *mem, cmark_node *parent, cmark_reference_map *refmap, int options) { subject subj; subject_from_buf(mem, &subj, &parent->content, refmap); cmark_chunk_rtrim(&subj.input); while (!is_eof(&subj) && parse_inline(&subj, parent, options)) ; process_emphasis(&subj, NULL); // free bracket and delim stack while (subj.last_delim) { remove_delimiter(&subj, subj.last_delim); } while (subj.last_bracket) { pop_bracket(&subj); } }
static void process_emphasis(subject *subj, delimiter *start_delim) { delimiter *closer = subj->last_delim; delimiter *opener; // move back to first relevant delim. while (closer != NULL && closer->previous != start_delim) { closer = closer->previous; } // now move forward, looking for closers, and handling each while (closer != NULL) { if (closer->can_close && (closer->delim_char == '*' || closer->delim_char == '_')) { // Now look backwards for first matching opener: opener = closer->previous; while (opener != NULL && opener != start_delim) { if (opener->delim_char == closer->delim_char && opener->can_open) { break; } opener = opener->previous; } if (opener != NULL && opener != start_delim) { closer = S_insert_emph(subj, opener, closer); } else { closer = closer->next; } } else { closer = closer->next; } } // free all delimiters in list until start_delim: while (subj->last_delim != start_delim) { remove_delimiter(subj, subj->last_delim); } }
// Return a link, an image, or a literal close bracket. static cmark_node* handle_close_bracket(subject* subj, cmark_node *parent) { int initial_pos; int starturl, endurl, starttitle, endtitle, endall; int n; int sps; cmark_reference *ref; bool is_image = false; cmark_chunk url_chunk, title_chunk; unsigned char *url, *title; delimiter *opener; cmark_node *link_text; cmark_node *inl; cmark_chunk raw_label; int found_label; advance(subj); // advance past ] initial_pos = subj->pos; // look through list of delimiters for a [ or ! opener = subj->last_delim; while (opener) { if (opener->delim_char == '[' || opener->delim_char == '!') { break; } opener = opener->previous; } if (opener == NULL) { return make_str(cmark_chunk_literal("]")); } if (!opener->active) { // take delimiter off stack remove_delimiter(subj, opener); return make_str(cmark_chunk_literal("]")); } // If we got here, we matched a potential link/image text. is_image = opener->delim_char == '!'; link_text = opener->inl_text->next; // Now we check to see if it's a link/image. // First, look for an inline link. if (peek_char(subj) == '(' && ((sps = scan_spacechars(&subj->input, subj->pos + 1)) > -1) && ((n = scan_link_url(&subj->input, subj->pos + 1 + sps)) > -1)) { // try to parse an explicit link: starturl = subj->pos + 1 + sps; // after ( endurl = starturl + n; starttitle = endurl + scan_spacechars(&subj->input, endurl); // ensure there are spaces btw url and title endtitle = (starttitle == endurl) ? starttitle : starttitle + scan_link_title(&subj->input, starttitle); endall = endtitle + scan_spacechars(&subj->input, endtitle); if (peek_at(subj, endall) == ')') { subj->pos = endall + 1; url_chunk = cmark_chunk_dup(&subj->input, starturl, endurl - starturl); title_chunk = cmark_chunk_dup(&subj->input, starttitle, endtitle - starttitle); url = cmark_clean_url(&url_chunk); title = cmark_clean_title(&title_chunk); cmark_chunk_free(&url_chunk); cmark_chunk_free(&title_chunk); goto match; } else { goto noMatch; } } // Next, look for a following [link label] that matches in refmap. // skip spaces subj->pos = subj->pos + scan_spacechars(&subj->input, subj->pos); raw_label = cmark_chunk_literal(""); found_label = link_label(subj, &raw_label); if (!found_label || raw_label.len == 0) { cmark_chunk_free(&raw_label); raw_label = cmark_chunk_dup(&subj->input, opener->position, initial_pos - opener->position - 1); } if (!found_label) { // If we have a shortcut reference link, back up // to before the spacse we skipped. subj->pos = initial_pos; } ref = cmark_reference_lookup(subj->refmap, &raw_label); cmark_chunk_free(&raw_label); if (ref != NULL) { // found url = bufdup(ref->url); title = bufdup(ref->title); goto match; } else { goto noMatch; } noMatch: // If we fall through to here, it means we didn't match a link: remove_delimiter(subj, opener); // remove this opener from delimiter list subj->pos = initial_pos; return make_str(cmark_chunk_literal("]")); match: inl = opener->inl_text; inl->type = is_image ? NODE_IMAGE : NODE_LINK; cmark_chunk_free(&inl->as.literal); inl->first_child = link_text; process_emphasis(subj, opener->previous); inl->as.link.url = url; inl->as.link.title = title; inl->next = NULL; if (link_text) { cmark_node *tmp; link_text->prev = NULL; for (tmp = link_text; tmp->next != NULL; tmp = tmp->next) { tmp->parent = inl; } tmp->parent = inl; inl->last_child = tmp; } parent->last_child = inl; // process_emphasis will remove this delimiter and all later ones. // Now, if we have a link, we also want to deactivate earlier link // delimiters. (This code can be removed if we decide to allow links // inside links.) if (!is_image) { opener = subj->last_delim; while (opener != NULL) { if (opener->delim_char == '[') { if (!opener->active) { break; } else { opener->active = false; } } opener = opener->previous; } } return NULL; }
static delimiter* S_insert_emph(subject *subj, delimiter *opener, delimiter *closer) { delimiter *delim, *tmp_delim; int use_delims; cmark_node *opener_inl = opener->inl_text; cmark_node *closer_inl = closer->inl_text; int opener_num_chars = opener_inl->as.literal.len; int closer_num_chars = closer_inl->as.literal.len; cmark_node *tmp, *emph, *first_child, *last_child; // calculate the actual number of characters used from this closer if (closer_num_chars < 3 || opener_num_chars < 3) { use_delims = closer_num_chars <= opener_num_chars ? closer_num_chars : opener_num_chars; } else { // closer and opener both have >= 3 characters use_delims = closer_num_chars % 2 == 0 ? 2 : 1; } // remove used characters from associated inlines. opener_num_chars -= use_delims; closer_num_chars -= use_delims; opener_inl->as.literal.len = opener_num_chars; closer_inl->as.literal.len = closer_num_chars; // free delimiters between opener and closer delim = closer->previous; while (delim != NULL && delim != opener) { tmp_delim = delim->previous; remove_delimiter(subj, delim); delim = tmp_delim; } first_child = opener_inl->next; last_child = closer_inl->prev; // if opener has 0 characters, remove it and its associated inline if (opener_num_chars == 0) { // replace empty opener inline with emph cmark_chunk_free(&(opener_inl->as.literal)); emph = opener_inl; emph->type = use_delims == 1 ? NODE_EMPH : NODE_STRONG; // remove opener from list remove_delimiter(subj, opener); } else { // create new emph or strong, and splice it in to our inlines // between the opener and closer emph = use_delims == 1 ? make_emph() : make_strong(); emph->parent = opener_inl->parent; emph->prev = opener_inl; opener_inl->next = emph; } // push children below emph emph->next = closer_inl; closer_inl->prev = emph; emph->first_child = first_child; emph->last_child = last_child; // fix children pointers first_child->prev = NULL; last_child->next = NULL; for (tmp = first_child; tmp != NULL; tmp = tmp->next) { tmp->parent = emph; } // if closer has 0 characters, remove it and its associated inline if (closer_num_chars == 0) { // remove empty closer inline cmark_node_free(closer_inl); // remove closer from list tmp_delim = closer->next; remove_delimiter(subj, closer); closer = tmp_delim; } return closer; }
static void process_emphasis(subject *subj, delimiter *stack_bottom) { delimiter *closer = subj->last_delim; delimiter *opener; delimiter *old_closer; bool opener_found; int openers_bottom_index; delimiter *openers_bottom[6] = {stack_bottom, stack_bottom, stack_bottom, stack_bottom, stack_bottom, stack_bottom}; // move back to first relevant delim. while (closer != NULL && closer->previous != stack_bottom) { closer = closer->previous; } // now move forward, looking for closers, and handling each while (closer != NULL) { if (closer->can_close) { switch (closer->delim_char) { case '"': openers_bottom_index = 0; break; case '\'': openers_bottom_index = 1; break; case '_': openers_bottom_index = 2; break; case '*': openers_bottom_index = 3 + (closer->length % 3); break; default: assert(false); } // Now look backwards for first matching opener: opener = closer->previous; opener_found = false; while (opener != NULL && opener != openers_bottom[openers_bottom_index]) { if (opener->can_open && opener->delim_char == closer->delim_char) { // interior closer of size 2 can't match opener of size 1 // or of size 1 can't match 2 if (!(closer->can_open || opener->can_close) || ((opener->length + closer->length) % 3) != 0) { opener_found = true; break; } } opener = opener->previous; } old_closer = closer; if (closer->delim_char == '*' || closer->delim_char == '_') { if (opener_found) { closer = S_insert_emph(subj, opener, closer); } else { closer = closer->next; } } else if (closer->delim_char == '\'') { cmark_chunk_free(subj->mem, &closer->inl_text->as.literal); closer->inl_text->as.literal = cmark_chunk_literal(RIGHTSINGLEQUOTE); if (opener_found) { cmark_chunk_free(subj->mem, &opener->inl_text->as.literal); opener->inl_text->as.literal = cmark_chunk_literal(LEFTSINGLEQUOTE); } closer = closer->next; } else if (closer->delim_char == '"') { cmark_chunk_free(subj->mem, &closer->inl_text->as.literal); closer->inl_text->as.literal = cmark_chunk_literal(RIGHTDOUBLEQUOTE); if (opener_found) { cmark_chunk_free(subj->mem, &opener->inl_text->as.literal); opener->inl_text->as.literal = cmark_chunk_literal(LEFTDOUBLEQUOTE); } closer = closer->next; } if (!opener_found) { // set lower bound for future searches for openers openers_bottom[openers_bottom_index] = old_closer->previous; if (!old_closer->can_open) { // we can remove a closer that can't be an // opener, once we've seen there's no // matching opener: remove_delimiter(subj, old_closer); } } } else { closer = closer->next; } } // free all delimiters in list until stack_bottom: while (subj->last_delim != NULL && subj->last_delim != stack_bottom) { remove_delimiter(subj, subj->last_delim); } }
static void process_emphasis(subject *subj, delimiter *stack_bottom) { delimiter *closer = subj->last_delim; delimiter *opener; delimiter *old_closer; bool opener_found; bool odd_match; delimiter *openers_bottom[128]; // initialize openers_bottom: openers_bottom['*'] = stack_bottom; openers_bottom['_'] = stack_bottom; openers_bottom['\''] = stack_bottom; openers_bottom['"'] = stack_bottom; // move back to first relevant delim. while (closer != NULL && closer->previous != stack_bottom) { closer = closer->previous; } // now move forward, looking for closers, and handling each while (closer != NULL) { if (closer->can_close) { // Now look backwards for first matching opener: opener = closer->previous; opener_found = false; odd_match = false; while (opener != NULL && opener != stack_bottom && opener != openers_bottom[closer->delim_char]) { // interior closer of size 2 can't match opener of size 1 // or of size 1 can't match 2 odd_match = (closer->can_open || opener->can_close) && ((opener->inl_text->as.literal.len + closer->inl_text->as.literal.len) % 3 == 0); if (opener->delim_char == closer->delim_char && opener->can_open && !odd_match) { opener_found = true; break; } opener = opener->previous; } old_closer = closer; if (closer->delim_char == '*' || closer->delim_char == '_') { if (opener_found) { closer = S_insert_emph(subj, opener, closer); } else { closer = closer->next; } } else if (closer->delim_char == '\'') { cmark_chunk_free(subj->mem, &closer->inl_text->as.literal); closer->inl_text->as.literal = cmark_chunk_literal(RIGHTSINGLEQUOTE); if (opener_found) { cmark_chunk_free(subj->mem, &opener->inl_text->as.literal); opener->inl_text->as.literal = cmark_chunk_literal(LEFTSINGLEQUOTE); } closer = closer->next; } else if (closer->delim_char == '"') { cmark_chunk_free(subj->mem, &closer->inl_text->as.literal); closer->inl_text->as.literal = cmark_chunk_literal(RIGHTDOUBLEQUOTE); if (opener_found) { cmark_chunk_free(subj->mem, &opener->inl_text->as.literal); opener->inl_text->as.literal = cmark_chunk_literal(LEFTDOUBLEQUOTE); } closer = closer->next; } if (!opener_found && !odd_match) { // set lower bound for future searches for openers // (we don't do this with 'odd_match' set because // a ** that didn't match an earlier * might turn into // an opener, and the * might be matched by something // else. openers_bottom[old_closer->delim_char] = old_closer->previous; if (!old_closer->can_open) { // we can remove a closer that can't be an // opener, once we've seen there's no // matching opener: remove_delimiter(subj, old_closer); } } } else { closer = closer->next; } } // free all delimiters in list until stack_bottom: while (subj->last_delim != stack_bottom) { remove_delimiter(subj, subj->last_delim); } }
static void process_emphasis(subject *subj, delimiter *stack_bottom) { delimiter *closer = subj->last_delim; delimiter *opener; delimiter *old_closer; bool opener_found; delimiter *openers_bottom[128]; // initialize openers_bottom: openers_bottom['*'] = stack_bottom; openers_bottom['_'] = stack_bottom; openers_bottom['\''] = stack_bottom; openers_bottom['"'] = stack_bottom; // move back to first relevant delim. while (closer != NULL && closer->previous != stack_bottom) { closer = closer->previous; } // now move forward, looking for closers, and handling each while (closer != NULL) { if (closer->can_close && (closer->delim_char == '*' || closer->delim_char == '_' || closer->delim_char == '"' || closer->delim_char == '\'')) { // Now look backwards for first matching opener: opener = closer->previous; opener_found = false; while (opener != NULL && opener != stack_bottom && opener != openers_bottom[closer->delim_char]) { if (opener->delim_char == closer->delim_char && opener->can_open) { opener_found = true; break; } opener = opener->previous; } old_closer = closer; if (closer->delim_char == '*' || closer->delim_char == '_') { if (opener_found) { closer = S_insert_emph(subj, opener, closer); } else { closer = closer->next; } } else if (closer->delim_char == '\'') { cmark_chunk_free(&closer->inl_text->as.literal); closer->inl_text->as.literal = cmark_chunk_literal(RIGHTSINGLEQUOTE); if (opener_found) { cmark_chunk_free(&opener->inl_text->as.literal); opener->inl_text->as.literal = cmark_chunk_literal(LEFTSINGLEQUOTE); } closer = closer->next; } else if (closer->delim_char == '"') { cmark_chunk_free(&closer->inl_text->as.literal); closer->inl_text->as.literal = cmark_chunk_literal(RIGHTDOUBLEQUOTE); if (opener_found) { cmark_chunk_free(&opener->inl_text->as.literal); opener->inl_text->as.literal = cmark_chunk_literal(LEFTDOUBLEQUOTE); } closer = closer->next; } if (!opener_found) { // set lower bound for future searches for openers: openers_bottom[old_closer->delim_char] = old_closer->previous; if (!old_closer->can_open) { // we can remove a closer that can't be an // opener, once we've seen there's no // matching opener: remove_delimiter(subj, old_closer); } } } else { closer = closer->next; } } // free all delimiters in list until stack_bottom: while (subj->last_delim != stack_bottom) { remove_delimiter(subj, subj->last_delim); } }