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 = 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 );
0 commit comments