Пример #1
0
static CMARK_INLINE void outc(cmark_renderer *renderer, cmark_escaping escape,
                              int32_t c, unsigned char nextc) {
  bool needs_escaping = false;
  bool follows_digit =
      renderer->buffer->size > 0 &&
      cmark_isdigit(renderer->buffer->ptr[renderer->buffer->size - 1]);
  char encoded[ENCODED_SIZE];

  needs_escaping =
      c < 0x80 && escape != LITERAL &&
      ((escape == NORMAL &&
        (c < 0x20 ||
	 c == '*' || c == '_' || c == '[' || c == ']' || c == '#' || c == '<' ||
         c == '>' || c == '\\' || c == '`' || c == '!' ||
         (c == '&' && cmark_isalpha(nextc)) || (c == '!' && nextc == '[') ||
         (renderer->begin_content && (c == '-' || c == '+' || c == '=') &&
          // begin_content doesn't get set to false til we've passed digits
          // at the beginning of line, so...
          !follows_digit) ||
         (renderer->begin_content && (c == '.' || c == ')') && follows_digit &&
          (nextc == 0 || cmark_isspace(nextc))))) ||
       (escape == URL &&
        (c == '`' || c == '<' || c == '>' || cmark_isspace(c) || c == '\\' ||
         c == ')' || c == '(')) ||
       (escape == TITLE &&
        (c == '`' || c == '<' || c == '>' || c == '"' || c == '\\')));

  if (needs_escaping) {
    if (escape == URL && cmark_isspace(c)) {
      // use percent encoding for spaces
      snprintf(encoded, ENCODED_SIZE, "%%%2X", c);
      cmark_strbuf_puts(renderer->buffer, encoded);
      renderer->column += 3;
    } else if (cmark_ispunct(c)) {
      cmark_render_ascii(renderer, "\\");
      cmark_render_code_point(renderer, c);
    } else { // render as entity
      snprintf(encoded, ENCODED_SIZE, "&#%d;", c);
      cmark_strbuf_puts(renderer->buffer, encoded);
      renderer->column += strlen(encoded);
    }
  } else {
    cmark_render_code_point(renderer, c);
  }
}
Пример #2
0
// Attempts to parse a list item marker (bullet or enumerated).
// On success, returns length of the marker, and populates
// data with the details.  On failure, returns 0.
static bufsize_t parse_list_marker(cmark_chunk *input, bufsize_t pos,
                                   cmark_list **dataptr) {
  unsigned char c;
  bufsize_t startpos;
  cmark_list *data;

  startpos = pos;
  c = peek_at(input, pos);

  if (c == '*' || c == '-' || c == '+') {
    pos++;
    if (!cmark_isspace(peek_at(input, pos))) {
      return 0;
    }
    data = (cmark_list *)calloc(1, sizeof(*data));
    if (data == NULL) {
      return 0;
    } else {
      data->marker_offset = 0; // will be adjusted later
      data->list_type = CMARK_BULLET_LIST;
      data->bullet_char = c;
      data->start = 1;
      data->delimiter = CMARK_PERIOD_DELIM;
      data->tight = false;
    }
  } else if (cmark_isdigit(c)) {
    int start = 0;
    int digits = 0;

    do {
      start = (10 * start) + (peek_at(input, pos) - '0');
      pos++;
      digits++;
      // We limit to 9 digits to avoid overflow,
      // assuming max int is 2^31 - 1
      // This also seems to be the limit for 'start' in some browsers.
    } while (digits < 9 && cmark_isdigit(peek_at(input, pos)));

    c = peek_at(input, pos);
    if (c == '.' || c == ')') {
      pos++;
      if (!cmark_isspace(peek_at(input, pos))) {
        return 0;
      }
      data = (cmark_list *)calloc(1, sizeof(*data));
      if (data == NULL) {
        return 0;
      } else {
        data->marker_offset = 0; // will be adjusted later
        data->list_type = CMARK_ORDERED_LIST;
        data->bullet_char = 0;
        data->start = start;
        data->delimiter = (c == '.' ? CMARK_PERIOD_DELIM : CMARK_PAREN_DELIM);
        data->tight = false;
      }
    } else {
      return 0;
    }

  } else {
    return 0;
  }

  *dataptr = data;
  return (pos - startpos);
}
Пример #3
0
// Attempts to parse a list item marker (bullet or enumerated).
// On success, returns length of the marker, and populates
// data with the details.  On failure, returns 0.
static int parse_list_marker(cmark_chunk *input, int pos, cmark_list **dataptr)
{
	unsigned char c;
	int startpos;
	cmark_list *data;

	startpos = pos;
	c = peek_at(input, pos);

	if (c == '*' || c == '-' || c == '+') {
		pos++;
		if (!cmark_isspace(peek_at(input, pos))) {
			return 0;
		}
		data = (cmark_list *)calloc(1, sizeof(*data));
		if(data == NULL) {
			return 0;
		} else {
			data->marker_offset = 0; // will be adjusted later
			data->list_type = CMARK_BULLET_LIST;
			data->bullet_char = c;
			data->start = 1;
			data->delimiter = CMARK_PERIOD_DELIM;
			data->tight = false;
		}
	} else if (cmark_isdigit(c)) {
		int start = 0;

		do {
			start = (10 * start) + (peek_at(input, pos) - '0');
			pos++;
		} while (cmark_isdigit(peek_at(input, pos)));

		c = peek_at(input, pos);
		if (c == '.' || c == ')') {
			pos++;
			if (!cmark_isspace(peek_at(input, pos))) {
				return 0;
			}
			data = (cmark_list *)calloc(1, sizeof(*data));
			if(data == NULL) {
				return 0;
			} else {
				data->marker_offset = 0; // will be adjusted later
				data->list_type = CMARK_ORDERED_LIST;
				data->bullet_char = 0;
				data->start = start;
				data->delimiter = (c == '.' ? CMARK_PERIOD_DELIM : CMARK_PAREN_DELIM);
				data->tight = false;
			}
		} else {
			return 0;
		}

	} else {
		return 0;
	}

	*dataptr = data;
	return (pos - startpos);
}
Пример #4
0
static void S_out(cmark_renderer *renderer, cmark_node *node,
                  const char *source, bool wrap,
                  cmark_escaping escape) {
  int length = (int)strlen(source);
  unsigned char nextc;
  int32_t c;
  int i = 0;
  int last_nonspace;
  int len;
  cmark_chunk remainder = cmark_chunk_literal("");
  int k = renderer->buffer->size - 1;

  cmark_syntax_extension *ext = NULL;
  cmark_node *n = node;
  while (n && !ext) {
    ext = n->extension;
    if (!ext)
      n = n->parent;
  }
  if (ext && !ext->commonmark_escape_func)
    ext = NULL;

  wrap = wrap && !renderer->no_linebreaks;

  if (renderer->in_tight_list_item && renderer->need_cr > 1) {
    renderer->need_cr = 1;
  }
  while (renderer->need_cr) {
    if (k < 0 || renderer->buffer->ptr[k] == '\n') {
      k -= 1;
    } else {
      cmark_strbuf_putc(renderer->buffer, '\n');
      if (renderer->need_cr > 1) {
        cmark_strbuf_put(renderer->buffer, renderer->prefix->ptr,
                         renderer->prefix->size);
      }
    }
    renderer->column = 0;
    renderer->begin_line = true;
    renderer->begin_content = true;
    renderer->need_cr -= 1;
  }

  while (i < length) {
    if (renderer->begin_line) {
      cmark_strbuf_put(renderer->buffer, renderer->prefix->ptr,
                       renderer->prefix->size);
      // note: this assumes prefix is ascii:
      renderer->column = renderer->prefix->size;
    }

    len = cmark_utf8proc_iterate((const uint8_t *)source + i, length - i, &c);
    if (len == -1) { // error condition
      return;        // return without rendering rest of string
    }

    if (ext && ext->commonmark_escape_func(ext, node, c))
      cmark_strbuf_putc(renderer->buffer, '\\');

    nextc = source[i + len];
    if (c == 32 && wrap) {
      if (!renderer->begin_line) {
        last_nonspace = renderer->buffer->size;
        cmark_strbuf_putc(renderer->buffer, ' ');
        renderer->column += 1;
        renderer->begin_line = false;
        renderer->begin_content = false;
        // skip following spaces
        while (source[i + 1] == ' ') {
          i++;
        }
        // We don't allow breaks that make a digit the first character
        // because this causes problems with commonmark output.
        if (!cmark_isdigit(source[i + 1])) {
          renderer->last_breakable = last_nonspace;
        }
      }

    } else if (c == 10) {
      cmark_strbuf_putc(renderer->buffer, '\n');
      renderer->column = 0;
      renderer->begin_line = true;
      renderer->begin_content = true;
      renderer->last_breakable = 0;
    } else if (escape == LITERAL) {
      cmark_render_code_point(renderer, c);
      renderer->begin_line = false;
      // we don't set 'begin_content' to false til we've
      // finished parsing a digit.  Reason:  in commonmark
      // we need to escape a potential list marker after
      // a digit:
      renderer->begin_content =
          renderer->begin_content && cmark_isdigit((char)c) == 1;
    } else {
      (renderer->outc)(renderer, node, escape, c, nextc);
      renderer->begin_line = false;
      renderer->begin_content =
          renderer->begin_content && cmark_isdigit((char)c) == 1;
    }

    // If adding the character went beyond width, look for an
    // earlier place where the line could be broken:
    if (renderer->width > 0 && renderer->column > renderer->width &&
        !renderer->begin_line && renderer->last_breakable > 0) {

      // copy from last_breakable to remainder
      cmark_chunk_set_cstr(renderer->mem, &remainder,
                           (char *)renderer->buffer->ptr +
                               renderer->last_breakable + 1);
      // truncate at last_breakable
      cmark_strbuf_truncate(renderer->buffer, renderer->last_breakable);
      // add newline, prefix, and remainder
      cmark_strbuf_putc(renderer->buffer, '\n');
      cmark_strbuf_put(renderer->buffer, renderer->prefix->ptr,
                       renderer->prefix->size);
      cmark_strbuf_put(renderer->buffer, remainder.data, remainder.len);
      renderer->column = renderer->prefix->size + remainder.len;
      cmark_chunk_free(renderer->mem, &remainder);
      renderer->last_breakable = 0;
      renderer->begin_line = false;
      renderer->begin_content = false;
    }

    i += len;
  }
}