commonmarker 0.23.6 → 0.23.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of commonmarker might be problematic. Click here for more details.

@@ -15,6 +15,10 @@ bufsize_t _scan_autolink_uri(const unsigned char *p);
15
15
  bufsize_t _scan_autolink_email(const unsigned char *p);
16
16
  bufsize_t _scan_html_tag(const unsigned char *p);
17
17
  bufsize_t _scan_liberal_html_tag(const unsigned char *p);
18
+ bufsize_t _scan_html_comment(const unsigned char *p);
19
+ bufsize_t _scan_html_pi(const unsigned char *p);
20
+ bufsize_t _scan_html_declaration(const unsigned char *p);
21
+ bufsize_t _scan_html_cdata(const unsigned char *p);
18
22
  bufsize_t _scan_html_block_start(const unsigned char *p);
19
23
  bufsize_t _scan_html_block_start_7(const unsigned char *p);
20
24
  bufsize_t _scan_html_block_end_1(const unsigned char *p);
@@ -37,6 +41,10 @@ bufsize_t _scan_footnote_definition(const unsigned char *p);
37
41
  #define scan_autolink_email(c, n) _scan_at(&_scan_autolink_email, c, n)
38
42
  #define scan_html_tag(c, n) _scan_at(&_scan_html_tag, c, n)
39
43
  #define scan_liberal_html_tag(c, n) _scan_at(&_scan_liberal_html_tag, c, n)
44
+ #define scan_html_comment(c, n) _scan_at(&_scan_html_comment, c, n)
45
+ #define scan_html_pi(c, n) _scan_at(&_scan_html_pi, c, n)
46
+ #define scan_html_declaration(c, n) _scan_at(&_scan_html_declaration, c, n)
47
+ #define scan_html_cdata(c, n) _scan_at(&_scan_html_cdata, c, n)
40
48
  #define scan_html_block_start(c, n) _scan_at(&_scan_html_block_start, c, n)
41
49
  #define scan_html_block_start_7(c, n) _scan_at(&_scan_html_block_start_7, c, n)
42
50
  #define scan_html_block_end_1(c, n) _scan_at(&_scan_html_block_end_1, c, n)
@@ -67,6 +67,7 @@ static delimiter *insert(cmark_syntax_extension *self, cmark_parser *parser,
67
67
  strikethrough->end_column = closer->inl_text->start_column + closer->inl_text->as.literal.len - 1;
68
68
  cmark_node_free(closer->inl_text);
69
69
 
70
+ done:
70
71
  delim = closer;
71
72
  while (delim != NULL && delim != opener) {
72
73
  tmp_delim = delim->previous;
@@ -76,7 +77,6 @@ static delimiter *insert(cmark_syntax_extension *self, cmark_parser *parser,
76
77
 
77
78
  cmark_inline_parser_remove_delimiter(inline_parser, opener);
78
79
 
79
- done:
80
80
  return res;
81
81
  }
82
82
 
@@ -11,13 +11,21 @@
11
11
  #include "table.h"
12
12
  #include "cmark-gfm-core-extensions.h"
13
13
 
14
+ // Custom node flag, initialized in `create_table_extension`.
15
+ static cmark_node_internal_flags CMARK_NODE__TABLE_VISITED;
16
+
14
17
  cmark_node_type CMARK_NODE_TABLE, CMARK_NODE_TABLE_ROW,
15
18
  CMARK_NODE_TABLE_CELL;
16
19
 
20
+ typedef struct {
21
+ cmark_strbuf *buf;
22
+ int start_offset, end_offset, internal_offset;
23
+ } node_cell;
24
+
17
25
  typedef struct {
18
26
  uint16_t n_columns;
19
27
  int paragraph_offset;
20
- cmark_llist *cells;
28
+ node_cell *cells;
21
29
  } table_row;
22
30
 
23
31
  typedef struct {
@@ -29,24 +37,24 @@ typedef struct {
29
37
  bool is_header;
30
38
  } node_table_row;
31
39
 
32
- typedef struct {
33
- cmark_strbuf *buf;
34
- int start_offset, end_offset, internal_offset;
35
- } node_cell;
36
-
37
- static void free_table_cell(cmark_mem *mem, void *data) {
38
- node_cell *cell = (node_cell *)data;
40
+ static void free_table_cell(cmark_mem *mem, node_cell *cell) {
39
41
  cmark_strbuf_free((cmark_strbuf *)cell->buf);
40
42
  mem->free(cell->buf);
41
- mem->free(cell);
43
+ }
44
+
45
+ static void free_row_cells(cmark_mem *mem, table_row *row) {
46
+ while (row->n_columns > 0) {
47
+ free_table_cell(mem, &row->cells[--row->n_columns]);
48
+ }
49
+ mem->free(row->cells);
50
+ row->cells = NULL;
42
51
  }
43
52
 
44
53
  static void free_table_row(cmark_mem *mem, table_row *row) {
45
54
  if (!row)
46
55
  return;
47
56
 
48
- cmark_llist_free_full(mem, row->cells, (cmark_free_func)free_table_cell);
49
-
57
+ free_row_cells(mem, row);
50
58
  mem->free(row);
51
59
  }
52
60
 
@@ -111,6 +119,24 @@ static cmark_strbuf *unescape_pipes(cmark_mem *mem, unsigned char *string, bufsi
111
119
  return res;
112
120
  }
113
121
 
122
+ // Adds a new cell to the end of the row. A pointer to the new cell is returned
123
+ // for the caller to initialize.
124
+ static node_cell* append_row_cell(cmark_mem *mem, table_row *row) {
125
+ const uint32_t n_columns = row->n_columns + 1;
126
+ // realloc when n_columns is a power of 2
127
+ if ((n_columns & (n_columns-1)) == 0) {
128
+ // make sure we never wrap row->n_columns
129
+ // offset will != len and our exit will clean up as intended
130
+ if (n_columns > UINT16_MAX) {
131
+ return NULL;
132
+ }
133
+ // Use realloc to double the size of the buffer.
134
+ row->cells = (node_cell *)mem->realloc(row->cells, (2 * n_columns - 1) * sizeof(node_cell));
135
+ }
136
+ row->n_columns = (uint16_t)n_columns;
137
+ return &row->cells[n_columns-1];
138
+ }
139
+
114
140
  static table_row *row_from_string(cmark_syntax_extension *self,
115
141
  cmark_parser *parser, unsigned char *string,
116
142
  int len) {
@@ -152,24 +178,22 @@ static table_row *row_from_string(cmark_syntax_extension *self,
152
178
  cell_matched);
153
179
  cmark_strbuf_trim(cell_buf);
154
180
 
155
- node_cell *cell = (node_cell *)parser->mem->calloc(1, sizeof(*cell));
181
+ node_cell *cell = append_row_cell(parser->mem, row);
182
+ if (!cell) {
183
+ int_overflow_abort = 1;
184
+ cmark_strbuf_free(cell_buf);
185
+ parser->mem->free(cell_buf);
186
+ break;
187
+ }
156
188
  cell->buf = cell_buf;
157
189
  cell->start_offset = offset;
158
190
  cell->end_offset = offset + cell_matched - 1;
191
+ cell->internal_offset = 0;
159
192
 
160
- while (cell->start_offset > 0 && string[cell->start_offset - 1] != '|') {
193
+ while (cell->start_offset > row->paragraph_offset && string[cell->start_offset - 1] != '|') {
161
194
  --cell->start_offset;
162
195
  ++cell->internal_offset;
163
196
  }
164
-
165
- // make sure we never wrap row->n_columns
166
- // offset will != len and our exit will clean up as intended
167
- if (row->n_columns == UINT16_MAX) {
168
- int_overflow_abort = 1;
169
- break;
170
- }
171
- row->n_columns += 1;
172
- row->cells = cmark_llist_append(parser->mem, row->cells, cell);
173
197
  }
174
198
 
175
199
  offset += cell_matched + pipe_matched;
@@ -187,9 +211,7 @@ static table_row *row_from_string(cmark_syntax_extension *self,
187
211
  if (row_end_offset && offset != len) {
188
212
  row->paragraph_offset = offset;
189
213
 
190
- cmark_llist_free_full(parser->mem, row->cells, (cmark_free_func)free_table_cell);
191
- row->cells = NULL;
192
- row->n_columns = 0;
214
+ free_row_cells(parser->mem, row);
193
215
 
194
216
  // Scan past the (optional) leading pipe.
195
217
  offset += scan_table_cell_end(string, len, offset);
@@ -240,6 +262,10 @@ static cmark_node *try_opening_table_header(cmark_syntax_extension *self,
240
262
  const char *parent_string;
241
263
  uint16_t i;
242
264
 
265
+ if (parent_container->flags & CMARK_NODE__TABLE_VISITED) {
266
+ return parent_container;
267
+ }
268
+
243
269
  if (!scan_table_start(input, len, cmark_parser_get_first_nonspace(parser))) {
244
270
  return parent_container;
245
271
  }
@@ -267,6 +293,7 @@ static cmark_node *try_opening_table_header(cmark_syntax_extension *self,
267
293
  free_table_row(parser->mem, marker_row);
268
294
  free_table_row(parser->mem, header_row);
269
295
  cmark_arena_pop();
296
+ parent_container->flags |= CMARK_NODE__TABLE_VISITED;
270
297
  return parent_container;
271
298
  }
272
299
 
@@ -303,9 +330,8 @@ static cmark_node *try_opening_table_header(cmark_syntax_extension *self,
303
330
  // since we populate the alignments array based on marker_row->cells
304
331
  uint8_t *alignments =
305
332
  (uint8_t *)parser->mem->calloc(marker_row->n_columns, sizeof(uint8_t));
306
- cmark_llist *it = marker_row->cells;
307
- for (i = 0; it; it = it->next, ++i) {
308
- node_cell *node = (node_cell *)it->data;
333
+ for (i = 0; i < marker_row->n_columns; ++i) {
334
+ node_cell *node = &marker_row->cells[i];
309
335
  bool left = node->buf->ptr[0] == ':', right = node->buf->ptr[node->buf->size - 1] == ':';
310
336
 
311
337
  if (left && right)
@@ -328,10 +354,8 @@ static cmark_node *try_opening_table_header(cmark_syntax_extension *self,
328
354
  ntr->is_header = true;
329
355
 
330
356
  {
331
- cmark_llist *tmp;
332
-
333
- for (tmp = header_row->cells; tmp; tmp = tmp->next) {
334
- node_cell *cell = (node_cell *) tmp->data;
357
+ for (i = 0; i < header_row->n_columns; ++i) {
358
+ node_cell *cell = &header_row->cells[i];
335
359
  cmark_node *header_cell = cmark_parser_add_child(parser, table_header,
336
360
  CMARK_NODE_TABLE_CELL, parent_container->start_column + cell->start_offset);
337
361
  header_cell->start_line = header_cell->end_line = parent_container->start_line;
@@ -378,11 +402,10 @@ static cmark_node *try_opening_table_row(cmark_syntax_extension *self,
378
402
  }
379
403
 
380
404
  {
381
- cmark_llist *tmp;
382
405
  int i, table_columns = get_n_table_columns(parent_container);
383
406
 
384
- for (tmp = row->cells, i = 0; tmp && i < table_columns; tmp = tmp->next, ++i) {
385
- node_cell *cell = (node_cell *) tmp->data;
407
+ for (i = 0; i < row->n_columns && i < table_columns; ++i) {
408
+ node_cell *cell = &row->cells[i];
386
409
  cmark_node *node = cmark_parser_add_child(parser, table_row_block,
387
410
  CMARK_NODE_TABLE_CELL, parent_container->start_column + cell->start_offset);
388
411
  node->internal_offset = cell->internal_offset;
@@ -785,6 +808,7 @@ static int escape(cmark_syntax_extension *self, cmark_node *node, int c) {
785
808
  cmark_syntax_extension *create_table_extension(void) {
786
809
  cmark_syntax_extension *self = cmark_syntax_extension_new("table");
787
810
 
811
+ cmark_register_node_flag(&CMARK_NODE__TABLE_VISITED);
788
812
  cmark_syntax_extension_set_match_block_func(self, matches);
789
813
  cmark_syntax_extension_set_open_block_func(self, try_opening_table_block);
790
814
  cmark_syntax_extension_set_get_type_string_func(self, get_type_string);
@@ -33,20 +33,22 @@ module CommonMarker
33
33
  format: [:html, :xml, :commonmark, :plaintext].freeze,
34
34
  }.freeze
35
35
 
36
- def self.process_options(option, type)
37
- case option
38
- when Symbol
39
- OPTS.fetch(type).fetch(option)
40
- when Array
41
- raise TypeError if option.none?
36
+ class << self
37
+ def process_options(option, type)
38
+ case option
39
+ when Symbol
40
+ OPTS.fetch(type).fetch(option)
41
+ when Array
42
+ raise TypeError if option.none?
42
43
 
43
- # neckbearding around. the map will both check the opts and then bitwise-OR it
44
- OPTS.fetch(type).fetch_values(*option).inject(0, :|)
45
- else
46
- raise TypeError, "option type must be a valid symbol or array of symbols within the #{name}::OPTS[:#{type}] context"
44
+ # neckbearding around. the map will both check the opts and then bitwise-OR it
45
+ OPTS.fetch(type).fetch_values(*option).inject(0, :|)
46
+ else
47
+ raise TypeError, "option type must be a valid symbol or array of symbols within the #{name}::OPTS[:#{type}] context"
48
+ end
49
+ rescue KeyError => e
50
+ raise TypeError, "option ':#{e.key}' does not exist for #{name}::OPTS[:#{type}]"
47
51
  end
48
- rescue KeyError => e
49
- raise TypeError, "option ':#{e.key}' does not exist for #{name}::OPTS[:#{type}]"
50
- end
52
+ end
51
53
  end
52
54
  end
@@ -113,7 +113,7 @@ module CommonMarker
113
113
  )
114
114
  (?=\s|>|/>)
115
115
  }xi,
116
- '&lt;\1'
116
+ '&lt;\1',
117
117
  )
118
118
  else
119
119
  str
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CommonMarker
4
- VERSION = "0.23.6"
4
+ VERSION = "0.23.8"
5
5
  end
data/lib/commonmarker.rb CHANGED
@@ -12,32 +12,34 @@ begin
12
12
  require "awesome_print"
13
13
  rescue LoadError; end # rubocop:disable Lint/SuppressedException
14
14
  module CommonMarker
15
- # Public: Parses a Markdown string into an HTML string.
16
- #
17
- # text - A {String} of text
18
- # option - Either a {Symbol} or {Array of Symbol}s indicating the render options
19
- # extensions - An {Array of Symbol}s indicating the extensions to use
20
- #
21
- # Returns a {String} of converted HTML.
22
- def self.render_html(text, options = :DEFAULT, extensions = [])
23
- raise TypeError, "text must be a String; got a #{text.class}!" unless text.is_a?(String)
15
+ class << self
16
+ # Public: Parses a Markdown string into an HTML string.
17
+ #
18
+ # text - A {String} of text
19
+ # option - Either a {Symbol} or {Array of Symbol}s indicating the render options
20
+ # extensions - An {Array of Symbol}s indicating the extensions to use
21
+ #
22
+ # Returns a {String} of converted HTML.
23
+ def render_html(text, options = :DEFAULT, extensions = [])
24
+ raise TypeError, "text must be a String; got a #{text.class}!" unless text.is_a?(String)
24
25
 
25
- opts = Config.process_options(options, :render)
26
- Node.markdown_to_html(text.encode("UTF-8"), opts, extensions)
27
- end
26
+ opts = Config.process_options(options, :render)
27
+ Node.markdown_to_html(text.encode("UTF-8"), opts, extensions)
28
+ end
28
29
 
29
- # Public: Parses a Markdown string into a `document` node.
30
- #
31
- # string - {String} to be parsed
32
- # option - A {Symbol} or {Array of Symbol}s indicating the parse options
33
- # extensions - An {Array of Symbol}s indicating the extensions to use
34
- #
35
- # Returns the `document` node.
36
- def self.render_doc(text, options = :DEFAULT, extensions = [])
37
- raise TypeError, "text must be a String; got a #{text.class}!" unless text.is_a?(String)
30
+ # Public: Parses a Markdown string into a `document` node.
31
+ #
32
+ # string - {String} to be parsed
33
+ # option - A {Symbol} or {Array of Symbol}s indicating the parse options
34
+ # extensions - An {Array of Symbol}s indicating the extensions to use
35
+ #
36
+ # Returns the `document` node.
37
+ def render_doc(text, options = :DEFAULT, extensions = [])
38
+ raise TypeError, "text must be a String; got a #{text.class}!" unless text.is_a?(String)
38
39
 
39
- opts = Config.process_options(options, :parse)
40
- text = text.encode("UTF-8")
41
- Node.parse_document(text, text.bytesize, opts, extensions)
42
- end
40
+ opts = Config.process_options(options, :parse)
41
+ text = text.encode("UTF-8")
42
+ Node.parse_document(text, text.bytesize, opts, extensions)
43
+ end
44
+ end
43
45
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: commonmarker
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.23.6
4
+ version: 0.23.8
5
5
  platform: ruby
6
6
  authors:
7
7
  - Garen Torikian
8
8
  - Ashe Connor
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-09-21 00:00:00.000000000 Z
12
+ date: 2023-01-31 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: awesome_print
@@ -139,7 +139,7 @@ dependencies:
139
139
  version: '0'
140
140
  description: A fast, safe, extensible parser for CommonMark. This wraps the official
141
141
  libcmark library.
142
- email:
142
+ email:
143
143
  executables:
144
144
  - commonmarker
145
145
  extensions:
@@ -234,7 +234,7 @@ licenses:
234
234
  - MIT
235
235
  metadata:
236
236
  rubygems_mfa_required: 'true'
237
- post_install_message:
237
+ post_install_message:
238
238
  rdoc_options:
239
239
  - "-x"
240
240
  - ext/commonmarker/cmark/.*
@@ -255,8 +255,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
255
255
  - !ruby/object:Gem::Version
256
256
  version: '0'
257
257
  requirements: []
258
- rubygems_version: 3.2.15
259
- signing_key:
258
+ rubygems_version: 3.3.26
259
+ signing_key:
260
260
  specification_version: 4
261
261
  summary: CommonMark parser and renderer. Written in C, wrapped in Ruby.
262
262
  test_files: []