Fossil SCM

Simplification of buffer management in the markdown formatter.

drh 2019-09-24 15:12 trunk
Commit f8e9197de45da6790918e3e7bcca9c05c1f5f3707e8eb1c3aa3f2ab57daea2e0
+40 -86
--- src/markdown.c
+++ src/markdown.c
@@ -85,11 +85,10 @@
8585
/* low level callbacks - NULL copies input directly into the output */
8686
void (*entity)(struct Blob *ob, struct Blob *entity, void *opaque);
8787
void (*normal_text)(struct Blob *ob, struct Blob *text, void *opaque);
8888
8989
/* renderer data */
90
- int max_work_stack; /* prevent arbitrary deep recursion, cf README */
9190
const char *emph_chars; /* chars that trigger emphasis rendering */
9291
void *opaque; /* opaque data send to every rendering callback */
9392
};
9493
9594
@@ -154,12 +153,12 @@
154153
/* render -- structure containing one particular render */
155154
struct render {
156155
struct mkd_renderer make;
157156
struct Blob refs;
158157
char_trigger active_char[256];
159
- int work_active;
160
- struct Blob *work;
158
+ int nBlobCache; /* Number of entries in aBlobCache */
159
+ struct Blob *aBlobCache[20]; /* Cache of Blobs available for reuse */
161160
};
162161
163162
164163
/* html_tag -- structure for quick HTML tag search (inspired from discount) */
165164
struct html_tag {
@@ -301,29 +300,32 @@
301300
sizeof block_tags[0],
302301
cmp_html_tag);
303302
}
304303
305304
306
-/* new_work_buffer -- get a new working buffer from the stack or create one */
305
+/* get a new working buffer from the cache or create one */
307306
static struct Blob *new_work_buffer(struct render *rndr){
308
- struct Blob *ret = 0;
309
-
310
- if( rndr->work_active < rndr->make.max_work_stack ){
311
- ret = rndr->work + rndr->work_active;
312
- rndr->work_active += 1;
313
- blob_reset(ret);
307
+ struct Blob *ret;
308
+ if( rndr->nBlobCache ){
309
+ ret = rndr->aBlobCache[--rndr->nBlobCache];
310
+ }else{
311
+ ret = fossil_malloc(sizeof(*ret));
314312
}
313
+ *ret = empty_blob;
315314
return ret;
316315
}
317316
318317
319
-/* release_work_buffer -- release the given working buffer */
318
+/* release the given working buffer back to the cache */
320319
static void release_work_buffer(struct render *rndr, struct Blob *buf){
321320
if( !buf ) return;
322
- assert(rndr->work_active>0 && buf==(rndr->work+rndr->work_active-1));
323
- rndr->work_active -= 1;
324321
blob_reset(buf);
322
+ if( rndr->nBlobCache < sizeof(rndr->aBlobCache)/sizeof(rndr->aBlobCache[0]) ){
323
+ rndr->aBlobCache[rndr->nBlobCache++] = buf;
324
+ }else{
325
+ fossil_free(buf);
326
+ }
325327
}
326328
327329
328330
329331
/****************************
@@ -1296,17 +1298,12 @@
12961298
}
12971299
beg = end;
12981300
}
12991301
13001302
if( rndr->make.blockquote ){
1301
- struct Blob fallback = BLOB_INITIALIZER;
1302
- if( out ){
1303
- parse_block(out, rndr, work_data, work_size);
1304
- }else{
1305
- blob_init(&fallback, work_data, work_size);
1306
- }
1307
- rndr->make.blockquote(ob, out ? out : &fallback, rndr->make.opaque);
1303
+ parse_block(out, rndr, work_data, work_size);
1304
+ rndr->make.blockquote(ob, out, rndr->make.opaque);
13081305
}
13091306
release_work_buffer(rndr, out);
13101307
return end;
13111308
}
13121309
@@ -1320,11 +1317,10 @@
13201317
){
13211318
size_t i = 0, end = 0;
13221319
int level = 0;
13231320
char *work_data = data;
13241321
size_t work_size = 0;
1325
- struct Blob fallback = BLOB_INITIALIZER;
13261322
13271323
while( i<size ){
13281324
for(end=i+1; end<size && data[end-1]!='\n'; end++);
13291325
if( is_empty(data+i, size-i)
13301326
|| (level = is_headerline(data+i, size-i))!= 0
@@ -1342,16 +1338,12 @@
13421338
while( work_size && data[work_size-1]=='\n' ){ work_size--; }
13431339
13441340
if( !level ){
13451341
if( rndr->make.paragraph ){
13461342
struct Blob *tmp = new_work_buffer(rndr);
1347
- if( tmp ){
1348
- parse_inline(tmp, rndr, work_data, work_size);
1349
- }else{
1350
- blob_init(&fallback, work_data, work_size);
1351
- }
1352
- rndr->make.paragraph(ob, tmp ? tmp : &fallback, rndr->make.opaque);
1343
+ parse_inline(tmp, rndr, work_data, work_size);
1344
+ rndr->make.paragraph(ob, tmp, rndr->make.opaque);
13531345
release_work_buffer(rndr, tmp);
13541346
}
13551347
}else{
13561348
if( work_size ){
13571349
size_t beg;
@@ -1360,17 +1352,13 @@
13601352
while( work_size && data[work_size]!='\n' ){ work_size--; }
13611353
beg = work_size+1;
13621354
while( work_size && data[work_size-1]=='\n'){ work_size--; }
13631355
if( work_size ){
13641356
struct Blob *tmp = new_work_buffer(rndr);
1365
- if( tmp ){
1366
- parse_inline(tmp, rndr, work_data, work_size);
1367
- }else{
1368
- blob_init (&fallback, work_data, work_size);
1369
- }
1357
+ parse_inline(tmp, rndr, work_data, work_size);
13701358
if( rndr->make.paragraph ){
1371
- rndr->make.paragraph(ob, tmp ? tmp : &fallback, rndr->make.opaque);
1359
+ rndr->make.paragraph(ob, tmp, rndr->make.opaque);
13721360
}
13731361
release_work_buffer(rndr, tmp);
13741362
work_data += beg;
13751363
work_size = i - beg;
13761364
}else{
@@ -1378,17 +1366,12 @@
13781366
}
13791367
}
13801368
13811369
if( rndr->make.header ){
13821370
struct Blob *span = new_work_buffer(rndr);
1383
- if( span ){
1384
- parse_inline(span, rndr, work_data, work_size);
1385
- rndr->make.header(ob, span, level, rndr->make.opaque);
1386
- }else{
1387
- blob_init(&fallback, work_data, work_size);
1388
- rndr->make.header(ob, &fallback, level, rndr->make.opaque);
1389
- }
1371
+ parse_inline(span, rndr, work_data, work_size);
1372
+ rndr->make.header(ob, span, level, rndr->make.opaque);
13901373
release_work_buffer(rndr, span);
13911374
}
13921375
}
13931376
return end;
13941377
}
@@ -1448,11 +1431,10 @@
14481431
struct render *rndr,
14491432
char *data,
14501433
size_t size,
14511434
int *flags
14521435
){
1453
- struct Blob fallback = BLOB_INITIALIZER;
14541436
struct Blob *work = 0, *inter = 0;
14551437
size_t beg = 0, end, pre, sublist = 0, orgpre = 0, i;
14561438
int in_empty = 0, has_inside_empty = 0;
14571439
14581440
/* keeping track of the first indentation prefix */
@@ -1473,11 +1455,10 @@
14731455
while( end<size && data[end-1]!='\n' ){ end++; }
14741456
14751457
/* getting working buffers */
14761458
work = new_work_buffer(rndr);
14771459
inter = new_work_buffer(rndr);
1478
- if( !work ) work = &fallback;
14791460
14801461
/* putting the first line into the working buffer */
14811462
blob_append(work, data+beg, end-beg);
14821463
beg = end;
14831464
@@ -1538,12 +1519,11 @@
15381519
/* non-recursive fallback when working buffer stack is full */
15391520
if( !inter ){
15401521
if( rndr->make.listitem ){
15411522
rndr->make.listitem(ob, work, *flags, rndr->make.opaque);
15421523
}
1543
- if( work!=&fallback ) release_work_buffer(rndr, work);
1544
- blob_reset(&fallback);
1524
+ release_work_buffer(rndr, work);
15451525
return beg;
15461526
}
15471527
15481528
/* render of li contents */
15491529
if( has_inside_empty ) *flags |= MKD_LI_BLOCK;
@@ -1574,12 +1554,11 @@
15741554
/* render of li itself */
15751555
if( rndr->make.listitem ){
15761556
rndr->make.listitem(ob, inter, *flags, rndr->make.opaque);
15771557
}
15781558
release_work_buffer(rndr, inter);
1579
- if( work!=&fallback ) release_work_buffer(rndr, work);
1580
- blob_reset(&fallback);
1559
+ release_work_buffer(rndr, work);
15811560
return beg;
15821561
}
15831562
15841563
15851564
/* parse_list -- parsing ordered or unordered list block */
@@ -1588,24 +1567,21 @@
15881567
struct render *rndr,
15891568
char *data,
15901569
size_t size,
15911570
int flags
15921571
){
1593
- struct Blob fallback = BLOB_INITIALIZER;
15941572
struct Blob *work = new_work_buffer(rndr);
15951573
size_t i = 0, j;
1596
- if( !work ) work = &fallback;
15971574
15981575
while( i<size ){
15991576
j = parse_listitem(work, rndr, data+i, size-i, &flags);
16001577
i += j;
16011578
if( !j || (flags & MKD_LI_END) ) break;
16021579
}
16031580
16041581
if( rndr->make.list ) rndr->make.list(ob, work, flags, rndr->make.opaque);
1605
- if( work!=&fallback ) release_work_buffer(rndr, work);
1606
- blob_reset(&fallback);
1582
+ release_work_buffer(rndr, work);
16071583
return i;
16081584
}
16091585
16101586
16111587
/* parse_atxheader -- parsing of atx-style headers */
@@ -1631,19 +1607,13 @@
16311607
while( end && (data[end-1]==' ' || data[end-1]=='\t') ){ end--; }
16321608
if( end<=i ) return parse_paragraph(ob, rndr, data, size);
16331609
16341610
span_size = end-span_beg;
16351611
if( rndr->make.header ){
1636
- struct Blob fallback = BLOB_INITIALIZER;
16371612
struct Blob *span = new_work_buffer(rndr);
1638
-
1639
- if( span ){
1640
- parse_inline(span, rndr, data+span_beg, span_size);
1641
- }else{
1642
- blob_init(&fallback, data+span_beg, span_size);
1643
- }
1644
- rndr->make.header(ob, span ? span : &fallback, level, rndr->make.opaque);
1613
+ parse_inline(span, rndr, data+span_beg, span_size);
1614
+ rndr->make.header(ob, span, level, rndr->make.opaque);
16451615
release_work_buffer(rndr, span);
16461616
}
16471617
return skip;
16481618
}
16491619
@@ -1800,19 +1770,13 @@
18001770
struct render *rndr, /* renderer description */
18011771
char *data, /* input text */
18021772
size_t size, /* input text size */
18031773
int flags /* table flags */
18041774
){
1805
- struct Blob fallback = BLOB_INITIALIZER;
18061775
struct Blob *span = new_work_buffer(rndr);
1807
-
1808
- if( span ){
1809
- parse_inline(span, rndr, data, size);
1810
- }else{
1811
- blob_init(&fallback, data, size);
1812
- }
1813
- rndr->make.table_cell(ob, span ? span : &fallback, flags, rndr->make.opaque);
1776
+ parse_inline(span, rndr, data, size);
1777
+ rndr->make.table_cell(ob, span, flags, rndr->make.opaque);
18141778
release_work_buffer(rndr, span);
18151779
}
18161780
18171781
18181782
/* parse_table_row -- parse an input line into a table row */
@@ -1878,17 +1842,11 @@
18781842
18791843
col++;
18801844
}
18811845
18821846
/* render the whole row and clean up */
1883
- if( cells ){
1884
- rndr->make.table_row(ob, cells, flags, rndr->make.opaque);
1885
- }else{
1886
- struct Blob fallback = BLOB_INITIALIZER;
1887
- blob_init(&fallback, data, total ? total : size);
1888
- rndr->make.table_row(ob, &fallback, flags, rndr->make.opaque);
1889
- }
1847
+ rndr->make.table_row(ob, cells, flags, rndr->make.opaque);
18901848
release_work_buffer(rndr, cells);
18911849
return total ? total : size;
18921850
}
18931851
18941852
@@ -1900,24 +1858,22 @@
19001858
size_t size
19011859
){
19021860
size_t i = 0, head_end, col;
19031861
size_t align_size = 0;
19041862
int *aligns = 0;
1905
- struct Blob fallback = BLOB_INITIALIZER;
19061863
struct Blob *head = 0;
19071864
struct Blob *rows = new_work_buffer(rndr);
1908
- if( !rows ) rows = &fallback;
19091865
19101866
/* skip the first (presumably header) line */
19111867
while( i<size && data[i]!='\n' ){ i++; }
19121868
head_end = i;
19131869
19141870
/* fallback on end of input */
19151871
if( i>=size ){
19161872
parse_table_row(rows, rndr, data, size, 0, 0, 0);
19171873
rndr->make.table(ob, 0, rows, rndr->make.opaque);
1918
- if( rows!=&fallback ) release_work_buffer(rndr, rows);
1874
+ release_work_buffer(rndr, rows);
19191875
return i;
19201876
}
19211877
19221878
/* attempt to parse a table rule, i.e. blanks, dash, colons and sep */
19231879
i++;
@@ -1982,12 +1938,12 @@
19821938
19831939
/* render the full table */
19841940
rndr->make.table(ob, head, rows, rndr->make.opaque);
19851941
19861942
/* cleanup */
1987
- if( head ) release_work_buffer(rndr, head);
1988
- if( rows!=&fallback ) release_work_buffer(rndr, rows);
1943
+ release_work_buffer(rndr, head);
1944
+ release_work_buffer(rndr, rows);
19891945
fossil_free(aligns);
19901946
return i;
19911947
}
19921948
19931949
@@ -2181,23 +2137,20 @@
21812137
struct Blob *ob, /* output blob for rendered text */
21822138
struct Blob *ib, /* input blob in markdown */
21832139
const struct mkd_renderer *rndrer /* renderer descriptor (callbacks) */
21842140
){
21852141
struct link_ref *lr;
2186
- struct Blob text = BLOB_INITIALIZER;
21872142
size_t i, beg, end = 0;
21882143
struct render rndr;
21892144
char *ib_data;
2145
+ Blob text = BLOB_INITIALIZER;
21902146
21912147
/* filling the render structure */
21922148
if( !rndrer ) return;
21932149
rndr.make = *rndrer;
2194
- if( rndr.make.max_work_stack<1 ) rndr.make.max_work_stack = 1;
2195
- rndr.work_active = 0;
2196
- rndr.work = fossil_malloc(rndr.make.max_work_stack * sizeof *rndr.work);
2197
- for(i=0; i<rndr.make.max_work_stack; i++) rndr.work[i] = text;
2198
- rndr.refs = text;
2150
+ rndr.nBlobCache = 0;
2151
+ rndr.refs = empty_blob;
21992152
for(i=0; i<256; i++) rndr.active_char[i] = 0;
22002153
if( (rndr.make.emphasis
22012154
|| rndr.make.double_emphasis
22022155
|| rndr.make.triple_emphasis)
22032156
&& rndr.make.emph_chars
@@ -2260,8 +2213,9 @@
22602213
blob_reset(&lr[i].id);
22612214
blob_reset(&lr[i].link);
22622215
blob_reset(&lr[i].title);
22632216
}
22642217
blob_reset(&rndr.refs);
2265
- blobarray_zero(rndr.work, rndr.make.max_work_stack);
2266
- fossil_free(rndr.work);
2218
+ for(i=0; i<rndr.nBlobCache; i++){
2219
+ fossil_free(rndr.aBlobCache[i]);
2220
+ }
22672221
}
22682222
--- src/markdown.c
+++ src/markdown.c
@@ -85,11 +85,10 @@
85 /* low level callbacks - NULL copies input directly into the output */
86 void (*entity)(struct Blob *ob, struct Blob *entity, void *opaque);
87 void (*normal_text)(struct Blob *ob, struct Blob *text, void *opaque);
88
89 /* renderer data */
90 int max_work_stack; /* prevent arbitrary deep recursion, cf README */
91 const char *emph_chars; /* chars that trigger emphasis rendering */
92 void *opaque; /* opaque data send to every rendering callback */
93 };
94
95
@@ -154,12 +153,12 @@
154 /* render -- structure containing one particular render */
155 struct render {
156 struct mkd_renderer make;
157 struct Blob refs;
158 char_trigger active_char[256];
159 int work_active;
160 struct Blob *work;
161 };
162
163
164 /* html_tag -- structure for quick HTML tag search (inspired from discount) */
165 struct html_tag {
@@ -301,29 +300,32 @@
301 sizeof block_tags[0],
302 cmp_html_tag);
303 }
304
305
306 /* new_work_buffer -- get a new working buffer from the stack or create one */
307 static struct Blob *new_work_buffer(struct render *rndr){
308 struct Blob *ret = 0;
309
310 if( rndr->work_active < rndr->make.max_work_stack ){
311 ret = rndr->work + rndr->work_active;
312 rndr->work_active += 1;
313 blob_reset(ret);
314 }
 
315 return ret;
316 }
317
318
319 /* release_work_buffer -- release the given working buffer */
320 static void release_work_buffer(struct render *rndr, struct Blob *buf){
321 if( !buf ) return;
322 assert(rndr->work_active>0 && buf==(rndr->work+rndr->work_active-1));
323 rndr->work_active -= 1;
324 blob_reset(buf);
 
 
 
 
 
325 }
326
327
328
329 /****************************
@@ -1296,17 +1298,12 @@
1296 }
1297 beg = end;
1298 }
1299
1300 if( rndr->make.blockquote ){
1301 struct Blob fallback = BLOB_INITIALIZER;
1302 if( out ){
1303 parse_block(out, rndr, work_data, work_size);
1304 }else{
1305 blob_init(&fallback, work_data, work_size);
1306 }
1307 rndr->make.blockquote(ob, out ? out : &fallback, rndr->make.opaque);
1308 }
1309 release_work_buffer(rndr, out);
1310 return end;
1311 }
1312
@@ -1320,11 +1317,10 @@
1320 ){
1321 size_t i = 0, end = 0;
1322 int level = 0;
1323 char *work_data = data;
1324 size_t work_size = 0;
1325 struct Blob fallback = BLOB_INITIALIZER;
1326
1327 while( i<size ){
1328 for(end=i+1; end<size && data[end-1]!='\n'; end++);
1329 if( is_empty(data+i, size-i)
1330 || (level = is_headerline(data+i, size-i))!= 0
@@ -1342,16 +1338,12 @@
1342 while( work_size && data[work_size-1]=='\n' ){ work_size--; }
1343
1344 if( !level ){
1345 if( rndr->make.paragraph ){
1346 struct Blob *tmp = new_work_buffer(rndr);
1347 if( tmp ){
1348 parse_inline(tmp, rndr, work_data, work_size);
1349 }else{
1350 blob_init(&fallback, work_data, work_size);
1351 }
1352 rndr->make.paragraph(ob, tmp ? tmp : &fallback, rndr->make.opaque);
1353 release_work_buffer(rndr, tmp);
1354 }
1355 }else{
1356 if( work_size ){
1357 size_t beg;
@@ -1360,17 +1352,13 @@
1360 while( work_size && data[work_size]!='\n' ){ work_size--; }
1361 beg = work_size+1;
1362 while( work_size && data[work_size-1]=='\n'){ work_size--; }
1363 if( work_size ){
1364 struct Blob *tmp = new_work_buffer(rndr);
1365 if( tmp ){
1366 parse_inline(tmp, rndr, work_data, work_size);
1367 }else{
1368 blob_init (&fallback, work_data, work_size);
1369 }
1370 if( rndr->make.paragraph ){
1371 rndr->make.paragraph(ob, tmp ? tmp : &fallback, rndr->make.opaque);
1372 }
1373 release_work_buffer(rndr, tmp);
1374 work_data += beg;
1375 work_size = i - beg;
1376 }else{
@@ -1378,17 +1366,12 @@
1378 }
1379 }
1380
1381 if( rndr->make.header ){
1382 struct Blob *span = new_work_buffer(rndr);
1383 if( span ){
1384 parse_inline(span, rndr, work_data, work_size);
1385 rndr->make.header(ob, span, level, rndr->make.opaque);
1386 }else{
1387 blob_init(&fallback, work_data, work_size);
1388 rndr->make.header(ob, &fallback, level, rndr->make.opaque);
1389 }
1390 release_work_buffer(rndr, span);
1391 }
1392 }
1393 return end;
1394 }
@@ -1448,11 +1431,10 @@
1448 struct render *rndr,
1449 char *data,
1450 size_t size,
1451 int *flags
1452 ){
1453 struct Blob fallback = BLOB_INITIALIZER;
1454 struct Blob *work = 0, *inter = 0;
1455 size_t beg = 0, end, pre, sublist = 0, orgpre = 0, i;
1456 int in_empty = 0, has_inside_empty = 0;
1457
1458 /* keeping track of the first indentation prefix */
@@ -1473,11 +1455,10 @@
1473 while( end<size && data[end-1]!='\n' ){ end++; }
1474
1475 /* getting working buffers */
1476 work = new_work_buffer(rndr);
1477 inter = new_work_buffer(rndr);
1478 if( !work ) work = &fallback;
1479
1480 /* putting the first line into the working buffer */
1481 blob_append(work, data+beg, end-beg);
1482 beg = end;
1483
@@ -1538,12 +1519,11 @@
1538 /* non-recursive fallback when working buffer stack is full */
1539 if( !inter ){
1540 if( rndr->make.listitem ){
1541 rndr->make.listitem(ob, work, *flags, rndr->make.opaque);
1542 }
1543 if( work!=&fallback ) release_work_buffer(rndr, work);
1544 blob_reset(&fallback);
1545 return beg;
1546 }
1547
1548 /* render of li contents */
1549 if( has_inside_empty ) *flags |= MKD_LI_BLOCK;
@@ -1574,12 +1554,11 @@
1574 /* render of li itself */
1575 if( rndr->make.listitem ){
1576 rndr->make.listitem(ob, inter, *flags, rndr->make.opaque);
1577 }
1578 release_work_buffer(rndr, inter);
1579 if( work!=&fallback ) release_work_buffer(rndr, work);
1580 blob_reset(&fallback);
1581 return beg;
1582 }
1583
1584
1585 /* parse_list -- parsing ordered or unordered list block */
@@ -1588,24 +1567,21 @@
1588 struct render *rndr,
1589 char *data,
1590 size_t size,
1591 int flags
1592 ){
1593 struct Blob fallback = BLOB_INITIALIZER;
1594 struct Blob *work = new_work_buffer(rndr);
1595 size_t i = 0, j;
1596 if( !work ) work = &fallback;
1597
1598 while( i<size ){
1599 j = parse_listitem(work, rndr, data+i, size-i, &flags);
1600 i += j;
1601 if( !j || (flags & MKD_LI_END) ) break;
1602 }
1603
1604 if( rndr->make.list ) rndr->make.list(ob, work, flags, rndr->make.opaque);
1605 if( work!=&fallback ) release_work_buffer(rndr, work);
1606 blob_reset(&fallback);
1607 return i;
1608 }
1609
1610
1611 /* parse_atxheader -- parsing of atx-style headers */
@@ -1631,19 +1607,13 @@
1631 while( end && (data[end-1]==' ' || data[end-1]=='\t') ){ end--; }
1632 if( end<=i ) return parse_paragraph(ob, rndr, data, size);
1633
1634 span_size = end-span_beg;
1635 if( rndr->make.header ){
1636 struct Blob fallback = BLOB_INITIALIZER;
1637 struct Blob *span = new_work_buffer(rndr);
1638
1639 if( span ){
1640 parse_inline(span, rndr, data+span_beg, span_size);
1641 }else{
1642 blob_init(&fallback, data+span_beg, span_size);
1643 }
1644 rndr->make.header(ob, span ? span : &fallback, level, rndr->make.opaque);
1645 release_work_buffer(rndr, span);
1646 }
1647 return skip;
1648 }
1649
@@ -1800,19 +1770,13 @@
1800 struct render *rndr, /* renderer description */
1801 char *data, /* input text */
1802 size_t size, /* input text size */
1803 int flags /* table flags */
1804 ){
1805 struct Blob fallback = BLOB_INITIALIZER;
1806 struct Blob *span = new_work_buffer(rndr);
1807
1808 if( span ){
1809 parse_inline(span, rndr, data, size);
1810 }else{
1811 blob_init(&fallback, data, size);
1812 }
1813 rndr->make.table_cell(ob, span ? span : &fallback, flags, rndr->make.opaque);
1814 release_work_buffer(rndr, span);
1815 }
1816
1817
1818 /* parse_table_row -- parse an input line into a table row */
@@ -1878,17 +1842,11 @@
1878
1879 col++;
1880 }
1881
1882 /* render the whole row and clean up */
1883 if( cells ){
1884 rndr->make.table_row(ob, cells, flags, rndr->make.opaque);
1885 }else{
1886 struct Blob fallback = BLOB_INITIALIZER;
1887 blob_init(&fallback, data, total ? total : size);
1888 rndr->make.table_row(ob, &fallback, flags, rndr->make.opaque);
1889 }
1890 release_work_buffer(rndr, cells);
1891 return total ? total : size;
1892 }
1893
1894
@@ -1900,24 +1858,22 @@
1900 size_t size
1901 ){
1902 size_t i = 0, head_end, col;
1903 size_t align_size = 0;
1904 int *aligns = 0;
1905 struct Blob fallback = BLOB_INITIALIZER;
1906 struct Blob *head = 0;
1907 struct Blob *rows = new_work_buffer(rndr);
1908 if( !rows ) rows = &fallback;
1909
1910 /* skip the first (presumably header) line */
1911 while( i<size && data[i]!='\n' ){ i++; }
1912 head_end = i;
1913
1914 /* fallback on end of input */
1915 if( i>=size ){
1916 parse_table_row(rows, rndr, data, size, 0, 0, 0);
1917 rndr->make.table(ob, 0, rows, rndr->make.opaque);
1918 if( rows!=&fallback ) release_work_buffer(rndr, rows);
1919 return i;
1920 }
1921
1922 /* attempt to parse a table rule, i.e. blanks, dash, colons and sep */
1923 i++;
@@ -1982,12 +1938,12 @@
1982
1983 /* render the full table */
1984 rndr->make.table(ob, head, rows, rndr->make.opaque);
1985
1986 /* cleanup */
1987 if( head ) release_work_buffer(rndr, head);
1988 if( rows!=&fallback ) release_work_buffer(rndr, rows);
1989 fossil_free(aligns);
1990 return i;
1991 }
1992
1993
@@ -2181,23 +2137,20 @@
2181 struct Blob *ob, /* output blob for rendered text */
2182 struct Blob *ib, /* input blob in markdown */
2183 const struct mkd_renderer *rndrer /* renderer descriptor (callbacks) */
2184 ){
2185 struct link_ref *lr;
2186 struct Blob text = BLOB_INITIALIZER;
2187 size_t i, beg, end = 0;
2188 struct render rndr;
2189 char *ib_data;
 
2190
2191 /* filling the render structure */
2192 if( !rndrer ) return;
2193 rndr.make = *rndrer;
2194 if( rndr.make.max_work_stack<1 ) rndr.make.max_work_stack = 1;
2195 rndr.work_active = 0;
2196 rndr.work = fossil_malloc(rndr.make.max_work_stack * sizeof *rndr.work);
2197 for(i=0; i<rndr.make.max_work_stack; i++) rndr.work[i] = text;
2198 rndr.refs = text;
2199 for(i=0; i<256; i++) rndr.active_char[i] = 0;
2200 if( (rndr.make.emphasis
2201 || rndr.make.double_emphasis
2202 || rndr.make.triple_emphasis)
2203 && rndr.make.emph_chars
@@ -2260,8 +2213,9 @@
2260 blob_reset(&lr[i].id);
2261 blob_reset(&lr[i].link);
2262 blob_reset(&lr[i].title);
2263 }
2264 blob_reset(&rndr.refs);
2265 blobarray_zero(rndr.work, rndr.make.max_work_stack);
2266 fossil_free(rndr.work);
 
2267 }
2268
--- src/markdown.c
+++ src/markdown.c
@@ -85,11 +85,10 @@
85 /* low level callbacks - NULL copies input directly into the output */
86 void (*entity)(struct Blob *ob, struct Blob *entity, void *opaque);
87 void (*normal_text)(struct Blob *ob, struct Blob *text, void *opaque);
88
89 /* renderer data */
 
90 const char *emph_chars; /* chars that trigger emphasis rendering */
91 void *opaque; /* opaque data send to every rendering callback */
92 };
93
94
@@ -154,12 +153,12 @@
153 /* render -- structure containing one particular render */
154 struct render {
155 struct mkd_renderer make;
156 struct Blob refs;
157 char_trigger active_char[256];
158 int nBlobCache; /* Number of entries in aBlobCache */
159 struct Blob *aBlobCache[20]; /* Cache of Blobs available for reuse */
160 };
161
162
163 /* html_tag -- structure for quick HTML tag search (inspired from discount) */
164 struct html_tag {
@@ -301,29 +300,32 @@
300 sizeof block_tags[0],
301 cmp_html_tag);
302 }
303
304
305 /* get a new working buffer from the cache or create one */
306 static struct Blob *new_work_buffer(struct render *rndr){
307 struct Blob *ret;
308 if( rndr->nBlobCache ){
309 ret = rndr->aBlobCache[--rndr->nBlobCache];
310 }else{
311 ret = fossil_malloc(sizeof(*ret));
 
312 }
313 *ret = empty_blob;
314 return ret;
315 }
316
317
318 /* release the given working buffer back to the cache */
319 static void release_work_buffer(struct render *rndr, struct Blob *buf){
320 if( !buf ) return;
 
 
321 blob_reset(buf);
322 if( rndr->nBlobCache < sizeof(rndr->aBlobCache)/sizeof(rndr->aBlobCache[0]) ){
323 rndr->aBlobCache[rndr->nBlobCache++] = buf;
324 }else{
325 fossil_free(buf);
326 }
327 }
328
329
330
331 /****************************
@@ -1296,17 +1298,12 @@
1298 }
1299 beg = end;
1300 }
1301
1302 if( rndr->make.blockquote ){
1303 parse_block(out, rndr, work_data, work_size);
1304 rndr->make.blockquote(ob, out, rndr->make.opaque);
 
 
 
 
 
1305 }
1306 release_work_buffer(rndr, out);
1307 return end;
1308 }
1309
@@ -1320,11 +1317,10 @@
1317 ){
1318 size_t i = 0, end = 0;
1319 int level = 0;
1320 char *work_data = data;
1321 size_t work_size = 0;
 
1322
1323 while( i<size ){
1324 for(end=i+1; end<size && data[end-1]!='\n'; end++);
1325 if( is_empty(data+i, size-i)
1326 || (level = is_headerline(data+i, size-i))!= 0
@@ -1342,16 +1338,12 @@
1338 while( work_size && data[work_size-1]=='\n' ){ work_size--; }
1339
1340 if( !level ){
1341 if( rndr->make.paragraph ){
1342 struct Blob *tmp = new_work_buffer(rndr);
1343 parse_inline(tmp, rndr, work_data, work_size);
1344 rndr->make.paragraph(ob, tmp, rndr->make.opaque);
 
 
 
 
1345 release_work_buffer(rndr, tmp);
1346 }
1347 }else{
1348 if( work_size ){
1349 size_t beg;
@@ -1360,17 +1352,13 @@
1352 while( work_size && data[work_size]!='\n' ){ work_size--; }
1353 beg = work_size+1;
1354 while( work_size && data[work_size-1]=='\n'){ work_size--; }
1355 if( work_size ){
1356 struct Blob *tmp = new_work_buffer(rndr);
1357 parse_inline(tmp, rndr, work_data, work_size);
 
 
 
 
1358 if( rndr->make.paragraph ){
1359 rndr->make.paragraph(ob, tmp, rndr->make.opaque);
1360 }
1361 release_work_buffer(rndr, tmp);
1362 work_data += beg;
1363 work_size = i - beg;
1364 }else{
@@ -1378,17 +1366,12 @@
1366 }
1367 }
1368
1369 if( rndr->make.header ){
1370 struct Blob *span = new_work_buffer(rndr);
1371 parse_inline(span, rndr, work_data, work_size);
1372 rndr->make.header(ob, span, level, rndr->make.opaque);
 
 
 
 
 
1373 release_work_buffer(rndr, span);
1374 }
1375 }
1376 return end;
1377 }
@@ -1448,11 +1431,10 @@
1431 struct render *rndr,
1432 char *data,
1433 size_t size,
1434 int *flags
1435 ){
 
1436 struct Blob *work = 0, *inter = 0;
1437 size_t beg = 0, end, pre, sublist = 0, orgpre = 0, i;
1438 int in_empty = 0, has_inside_empty = 0;
1439
1440 /* keeping track of the first indentation prefix */
@@ -1473,11 +1455,10 @@
1455 while( end<size && data[end-1]!='\n' ){ end++; }
1456
1457 /* getting working buffers */
1458 work = new_work_buffer(rndr);
1459 inter = new_work_buffer(rndr);
 
1460
1461 /* putting the first line into the working buffer */
1462 blob_append(work, data+beg, end-beg);
1463 beg = end;
1464
@@ -1538,12 +1519,11 @@
1519 /* non-recursive fallback when working buffer stack is full */
1520 if( !inter ){
1521 if( rndr->make.listitem ){
1522 rndr->make.listitem(ob, work, *flags, rndr->make.opaque);
1523 }
1524 release_work_buffer(rndr, work);
 
1525 return beg;
1526 }
1527
1528 /* render of li contents */
1529 if( has_inside_empty ) *flags |= MKD_LI_BLOCK;
@@ -1574,12 +1554,11 @@
1554 /* render of li itself */
1555 if( rndr->make.listitem ){
1556 rndr->make.listitem(ob, inter, *flags, rndr->make.opaque);
1557 }
1558 release_work_buffer(rndr, inter);
1559 release_work_buffer(rndr, work);
 
1560 return beg;
1561 }
1562
1563
1564 /* parse_list -- parsing ordered or unordered list block */
@@ -1588,24 +1567,21 @@
1567 struct render *rndr,
1568 char *data,
1569 size_t size,
1570 int flags
1571 ){
 
1572 struct Blob *work = new_work_buffer(rndr);
1573 size_t i = 0, j;
 
1574
1575 while( i<size ){
1576 j = parse_listitem(work, rndr, data+i, size-i, &flags);
1577 i += j;
1578 if( !j || (flags & MKD_LI_END) ) break;
1579 }
1580
1581 if( rndr->make.list ) rndr->make.list(ob, work, flags, rndr->make.opaque);
1582 release_work_buffer(rndr, work);
 
1583 return i;
1584 }
1585
1586
1587 /* parse_atxheader -- parsing of atx-style headers */
@@ -1631,19 +1607,13 @@
1607 while( end && (data[end-1]==' ' || data[end-1]=='\t') ){ end--; }
1608 if( end<=i ) return parse_paragraph(ob, rndr, data, size);
1609
1610 span_size = end-span_beg;
1611 if( rndr->make.header ){
 
1612 struct Blob *span = new_work_buffer(rndr);
1613 parse_inline(span, rndr, data+span_beg, span_size);
1614 rndr->make.header(ob, span, level, rndr->make.opaque);
 
 
 
 
 
1615 release_work_buffer(rndr, span);
1616 }
1617 return skip;
1618 }
1619
@@ -1800,19 +1770,13 @@
1770 struct render *rndr, /* renderer description */
1771 char *data, /* input text */
1772 size_t size, /* input text size */
1773 int flags /* table flags */
1774 ){
 
1775 struct Blob *span = new_work_buffer(rndr);
1776 parse_inline(span, rndr, data, size);
1777 rndr->make.table_cell(ob, span, flags, rndr->make.opaque);
 
 
 
 
 
1778 release_work_buffer(rndr, span);
1779 }
1780
1781
1782 /* parse_table_row -- parse an input line into a table row */
@@ -1878,17 +1842,11 @@
1842
1843 col++;
1844 }
1845
1846 /* render the whole row and clean up */
1847 rndr->make.table_row(ob, cells, flags, rndr->make.opaque);
 
 
 
 
 
 
1848 release_work_buffer(rndr, cells);
1849 return total ? total : size;
1850 }
1851
1852
@@ -1900,24 +1858,22 @@
1858 size_t size
1859 ){
1860 size_t i = 0, head_end, col;
1861 size_t align_size = 0;
1862 int *aligns = 0;
 
1863 struct Blob *head = 0;
1864 struct Blob *rows = new_work_buffer(rndr);
 
1865
1866 /* skip the first (presumably header) line */
1867 while( i<size && data[i]!='\n' ){ i++; }
1868 head_end = i;
1869
1870 /* fallback on end of input */
1871 if( i>=size ){
1872 parse_table_row(rows, rndr, data, size, 0, 0, 0);
1873 rndr->make.table(ob, 0, rows, rndr->make.opaque);
1874 release_work_buffer(rndr, rows);
1875 return i;
1876 }
1877
1878 /* attempt to parse a table rule, i.e. blanks, dash, colons and sep */
1879 i++;
@@ -1982,12 +1938,12 @@
1938
1939 /* render the full table */
1940 rndr->make.table(ob, head, rows, rndr->make.opaque);
1941
1942 /* cleanup */
1943 release_work_buffer(rndr, head);
1944 release_work_buffer(rndr, rows);
1945 fossil_free(aligns);
1946 return i;
1947 }
1948
1949
@@ -2181,23 +2137,20 @@
2137 struct Blob *ob, /* output blob for rendered text */
2138 struct Blob *ib, /* input blob in markdown */
2139 const struct mkd_renderer *rndrer /* renderer descriptor (callbacks) */
2140 ){
2141 struct link_ref *lr;
 
2142 size_t i, beg, end = 0;
2143 struct render rndr;
2144 char *ib_data;
2145 Blob text = BLOB_INITIALIZER;
2146
2147 /* filling the render structure */
2148 if( !rndrer ) return;
2149 rndr.make = *rndrer;
2150 rndr.nBlobCache = 0;
2151 rndr.refs = empty_blob;
 
 
 
2152 for(i=0; i<256; i++) rndr.active_char[i] = 0;
2153 if( (rndr.make.emphasis
2154 || rndr.make.double_emphasis
2155 || rndr.make.triple_emphasis)
2156 && rndr.make.emph_chars
@@ -2260,8 +2213,9 @@
2213 blob_reset(&lr[i].id);
2214 blob_reset(&lr[i].link);
2215 blob_reset(&lr[i].title);
2216 }
2217 blob_reset(&rndr.refs);
2218 for(i=0; i<rndr.nBlobCache; i++){
2219 fossil_free(rndr.aBlobCache[i]);
2220 }
2221 }
2222
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -510,11 +510,10 @@
510510
/* low level elements */
511511
0, /* entities are copied verbatim */
512512
html_normal_text,
513513
514514
/* misc. parameters */
515
- 64, /* maximum stack */
516515
"*_", /* emphasis characters */
517516
0 /* opaque data */
518517
};
519518
html_renderer.opaque = output_title;
520519
if( output_title ) blob_reset(output_title);
521520
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -510,11 +510,10 @@
510 /* low level elements */
511 0, /* entities are copied verbatim */
512 html_normal_text,
513
514 /* misc. parameters */
515 64, /* maximum stack */
516 "*_", /* emphasis characters */
517 0 /* opaque data */
518 };
519 html_renderer.opaque = output_title;
520 if( output_title ) blob_reset(output_title);
521
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -510,11 +510,10 @@
510 /* low level elements */
511 0, /* entities are copied verbatim */
512 html_normal_text,
513
514 /* misc. parameters */
 
515 "*_", /* emphasis characters */
516 0 /* opaque data */
517 };
518 html_renderer.opaque = output_title;
519 if( output_title ) blob_reset(output_title);
520

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button