Fossil SCM

Code style tweaks, typos, and resolved a couple footnotes-related cosmetic TODOs. No functional changes.

stephan 2022-04-19 12:35 markdown-footnotes
Commit 3a5b3d5e4956d36b470b0435bb9de7bc5adab8c1de968660058ba662e8e2114f
+99 -69
--- src/markdown.c
+++ src/markdown.c
@@ -118,11 +118,13 @@
118118
119119
/**********************
120120
* EXPORTED FUNCTIONS *
121121
**********************/
122122
123
-/* markdown -- parses the input buffer and renders it into the output buffer */
123
+/*
124
+** markdown -- parses the input buffer and renders it into the output buffer.
125
+*/
124126
void markdown(
125127
struct Blob *ob,
126128
const struct Blob *ib,
127129
const struct mkd_renderer *rndr);
128130
@@ -135,18 +137,21 @@
135137
136138
/***************
137139
* LOCAL TYPES *
138140
***************/
139141
140
-/* link_ref -- reference to a link */
142
+/*
143
+** link_ref -- reference to a link.
144
+*/
141145
struct link_ref {
142146
struct Blob id; /* must be the first field as in footnote struct */
143147
struct Blob link;
144148
struct Blob title;
145149
};
146150
147
-/* A footnote's data.
151
+/*
152
+** A footnote's data.
148153
** id, text, and upc fields must be in that particular order.
149154
*/
150155
struct footnote {
151156
struct Blob id; /* must be the first field as in link_ref struct */
152157
struct Blob text; /* footnote's content that is rendered at the end */
@@ -216,12 +221,14 @@
216221
217222
/***************************
218223
* STATIC HELPER FUNCTIONS *
219224
***************************/
220225
221
-/* build_ref_id -- collapse whitespace from input text to make it a ref id */
222
-/* TODO: maybe also handle CR+LF line endings? */
226
+/*
227
+** build_ref_id -- collapse whitespace from input text to make it a ref id.
228
+** Potential TODO: maybe also handle CR+LF line endings?
229
+*/
223230
static int build_ref_id(struct Blob *id, const char *data, size_t size){
224231
size_t beg, i;
225232
char *id_data;
226233
227234
/* skip leading whitespace */
@@ -276,13 +283,15 @@
276283
struct link_ref *lra = (void *)a;
277284
struct link_ref *lrb = (void *)b;
278285
return blob_compare(&lra->id, &lrb->id);
279286
}
280287
281
-/* cmp_footnote_id -- comparison function for footnotes qsort.
282
- * Empty IDs sort last (in undetermined order).
283
- * Equal IDs are sorted in the order of definition in the source */
288
+/*
289
+** cmp_footnote_id -- comparison function for footnotes qsort.
290
+** Empty IDs sort last (in undetermined order).
291
+** Equal IDs are sorted in the order of definition in the source.
292
+*/
284293
static int cmp_footnote_id(const void *fna, const void *fnb){
285294
const struct footnote *a = fna, *b = fnb;
286295
const int szA = blob_size(&a->id), szB = blob_size(&b->id);
287296
if( szA ){
288297
if( szB ){
@@ -295,13 +304,15 @@
295304
if( a->defno > b->defno ) return 1;
296305
assert(!"reachable");
297306
return 0; /* should never reach here */
298307
}
299308
300
-/* cmp_footnote_sort -- comparison function for footnotes qsort.
301
- * Unreferenced footnotes (when nUsed == 0) sort last and
302
- * are sorted in the order of definition in the source */
309
+/*
310
+** cmp_footnote_sort -- comparison function for footnotes qsort.
311
+** Unreferenced footnotes (when nUsed == 0) sort last and
312
+** are sorted in the order of definition in the source.
313
+*/
303314
static int cmp_footnote_sort(const void *fna, const void *fnb){
304315
const struct footnote *a = fna, *b = fnb;
305316
int i, j;
306317
assert( a->nUsed >= 0 );
307318
assert( b->nUsed >= 0 );
@@ -652,12 +663,14 @@
652663
if( fossil_isalnum(after) ) return 0;
653664
return 1;
654665
}
655666
656667
657
-/* parse_emph1 -- parsing single emphasis */
658
-/* closed by a symbol not preceded by whitespace and not followed by symbol */
668
+/*
669
+** parse_emph1 -- parsing single emphasis.
670
+** closed by a symbol not preceded by whitespace and not followed by symbol.
671
+*/
659672
static size_t parse_emph1(
660673
struct Blob *ob,
661674
struct render *rndr,
662675
char *data,
663676
size_t size,
@@ -697,12 +710,13 @@
697710
}
698711
}
699712
return 0;
700713
}
701714
702
-
703
-/* parse_emph2 -- parsing single emphasis */
715
+/*
716
+** parse_emph2 -- parsing single emphasis.
717
+*/
704718
static size_t parse_emph2(
705719
struct Blob *ob,
706720
struct render *rndr,
707721
char *data,
708722
size_t size,
@@ -736,13 +750,14 @@
736750
i++;
737751
}
738752
return 0;
739753
}
740754
741
-
742
-/* parse_emph3 -- parsing single emphasis */
743
-/* finds the first closing tag, and delegates to the other emph */
755
+/*
756
+** parse_emph3 -- parsing single emphasis.
757
+** finds the first closing tag, and delegates to the other emph.
758
+*/
744759
static size_t parse_emph3(
745760
struct Blob *ob,
746761
struct render *rndr,
747762
char *data,
748763
size_t size,
@@ -784,12 +799,13 @@
784799
}
785800
}
786801
return 0;
787802
}
788803
789
-
790
-/* char_emphasis -- single and double emphasis parsing */
804
+/*
805
+** char_emphasis -- single and double emphasis parsing.
806
+*/
791807
static size_t char_emphasis(
792808
struct Blob *ob,
793809
struct render *rndr,
794810
char *data,
795811
size_t offset,
@@ -829,12 +845,13 @@
829845
return ret+3;
830846
}
831847
return 0;
832848
}
833849
834
-
835
-/* char_linebreak -- '\n' preceded by two spaces (assuming linebreak != 0) */
850
+/*
851
+** char_linebreak -- '\n' preceded by two spaces (assuming linebreak != 0).
852
+*/
836853
static size_t char_linebreak(
837854
struct Blob *ob,
838855
struct render *rndr,
839856
char *data,
840857
size_t offset,
@@ -844,12 +861,13 @@
844861
/* removing the last space from ob and rendering */
845862
if( blob_size(ob)>0 && blob_buffer(ob)[blob_size(ob)-1]==' ' ) ob->nUsed--;
846863
return rndr->make.linebreak(ob, rndr->make.opaque) ? 1 : 0;
847864
}
848865
849
-
850
-/* char_codespan -- '`' parsing a code span (assuming codespan != 0) */
866
+/*
867
+** char_codespan -- '`' parsing a code span (assuming codespan != 0).
868
+*/
851869
static size_t char_codespan(
852870
struct Blob *ob,
853871
struct render *rndr,
854872
char *data,
855873
size_t offset,
@@ -886,11 +904,13 @@
886904
}
887905
return end;
888906
}
889907
890908
891
-/* char_escape -- '\\' backslash escape */
909
+/*
910
+** char_escape -- '\\' backslash escape.
911
+*/
892912
static size_t char_escape(
893913
struct Blob *ob,
894914
struct render *rndr,
895915
char *data,
896916
size_t offset,
@@ -906,13 +926,14 @@
906926
}
907927
}
908928
return 2;
909929
}
910930
911
-
912
-/* char_entity -- '&' escaped when it doesn't belong to an entity */
913
-/* valid entities are assumed to be anything matching &#?[A-Za-z0-9]+; */
931
+/*
932
+** char_entity -- '&' escaped when it doesn't belong to an entity.
933
+** valid entities are assumed to be anything matching &#?[A-Za-z0-9]+;
934
+*/
914935
static size_t char_entity(
915936
struct Blob *ob,
916937
struct render *rndr,
917938
char *data,
918939
size_t offset,
@@ -942,12 +963,13 @@
942963
blob_append(ob, data, end);
943964
}
944965
return end;
945966
}
946967
947
-
948
-/* char_langle_tag -- '<' when tags or autolinks are allowed */
968
+/*
969
+** char_langle_tag -- '<' when tags or autolinks are allowed.
970
+*/
949971
static size_t char_langle_tag(
950972
struct Blob *ob,
951973
struct render *rndr,
952974
char *data,
953975
size_t offset,
@@ -972,12 +994,12 @@
972994
}else{
973995
return end;
974996
}
975997
}
976998
977
-
978
-/* get_link_inline -- extract inline-style link and title from
999
+/*
1000
+** get_link_inline -- extract inline-style link and title from
9791001
** parenthesed data
9801002
*/
9811003
static int get_link_inline(
9821004
struct Blob *link,
9831005
struct Blob *title,
@@ -1048,11 +1070,13 @@
10481070
/* this function always succeed */
10491071
return 0;
10501072
}
10511073
10521074
1053
-/* get_link_ref -- extract referenced link and title from id */
1075
+/*
1076
+** get_link_ref -- extract referenced link and title from id.
1077
+*/
10541078
static int get_link_ref(
10551079
struct render *rndr,
10561080
struct Blob *link,
10571081
struct Blob *title,
10581082
char *data,
@@ -1076,13 +1100,15 @@
10761100
blob_appendb(link, &lr->link);
10771101
blob_appendb(title, &lr->title);
10781102
return 0;
10791103
}
10801104
1081
-/* get_footnote() -- find a footnote by label, invoked during the 2nd pass.
1082
- * On success returns a footnote (after incrementing its nUsed field),
1083
- * otherwise returns NULL */
1105
+/*
1106
+** get_footnote() -- find a footnote by label, invoked during the 2nd pass.
1107
+** On success returns a footnote (after incrementing its nUsed field),
1108
+** otherwise returns NULL.
1109
+*/
10841110
static const struct footnote* get_footnote(
10851111
struct render *rndr,
10861112
const char *data,
10871113
size_t size
10881114
){
@@ -1105,14 +1131,15 @@
11051131
cleanup:
11061132
release_work_buffer( rndr, id );
11071133
return fn;
11081134
}
11091135
1110
-/* Counts characters in the blank prefix within at most nHalfLines.
1136
+/*
1137
+** Counts characters in the blank prefix within at most nHalfLines.
11111138
** A sequence of spaces and tabs counts as odd halfline,
11121139
** a newline counts as even halfline.
1113
-** If nHalfLines < 0 then procceed without constrains.
1140
+** If nHalfLines < 0 then proceed without constraints.
11141141
*/
11151142
static inline size_t sizeof_blank_prefix(
11161143
const char *data, size_t size, int nHalfLines
11171144
){
11181145
const char *p = data;
@@ -1134,22 +1161,24 @@
11341161
nHalfLines--;
11351162
}
11361163
return p-data;
11371164
}
11381165
1139
-/* Check if the data starts with a classlist token of the special form.
1166
+/*
1167
+** Check if the data starts with a classlist token of the special form.
11401168
** If so then return the length of that token, otherwise return 0.
11411169
**
11421170
** The token must start with a dot and must end with a colon;
11431171
** in between of these it must be a dot-separated list of words;
11441172
** each word may contain only alphanumeric characters and hyphens.
11451173
**
11461174
** If `bBlank` is non-zero then a blank character must follow
11471175
** the token's ending colon: otherwise function returns 0
1148
-** despite of the well-formed token.
1176
+** despite the well-formed token.
11491177
*/
1150
-size_t is_footnote_classlist(const char * const data, size_t size, int bBlank){
1178
+static size_t is_footnote_classlist(const char * const data, size_t size,
1179
+ int bBlank){
11511180
const char *p;
11521181
const char * const end = data+size;
11531182
if( data==end || *data != '.' ) return 0;
11541183
for(p=data+1; p!=end; p++){
11551184
if( fossil_isalnum(*p) || *p=='-' ) continue;
@@ -1164,13 +1193,16 @@
11641193
if( *p!='.' ) break;
11651194
}
11661195
return 0;
11671196
}
11681197
1169
-/* Adds unlabeled footnote to the rndr.
1170
- * If text is blank then returns 0,
1171
- * otherwise returns the address of the added footnote. */
1198
+/*
1199
+** Adds unlabeled footnote to the rndr. If text is blank then returns
1200
+** 0, otherwise returns the address of the added footnote, which lives
1201
+** in rndr->notes, noting that the pointer may be invalidated via
1202
+** reallocation the next time a footnote is added to that member.
1203
+*/
11721204
static inline const struct footnote* add_inline_footnote(
11731205
struct render *rndr,
11741206
const char *text,
11751207
size_t size
11761208
){
@@ -1202,12 +1234,13 @@
12021234
blob_append(&rndr->notes.all, (char *)&fn, sizeof fn);
12031235
return (struct footnote*)( blob_buffer(&rndr->notes.all)
12041236
+( blob_size(&rndr->notes.all)-sizeof fn ));
12051237
}
12061238
1207
-/* Return the offset of the matching closing bracket or 0 if not found.
1208
-** begin[0] must be either '[' or '('
1239
+/*
1240
+** Return the byte offset of the matching closing bracket or 0 if not
1241
+** found. begin[0] must be either '[' or '('.
12091242
**
12101243
** TODO: It seems that things like "\\(" are not handled correctly.
12111244
** That is historical behavior for a corner-case,
12121245
** so it's left as it is until somebody complains.
12131246
*/
@@ -1229,11 +1262,13 @@
12291262
}
12301263
}
12311264
return 0;
12321265
}
12331266
1234
-/* char_footnote -- '(': parsing a standalone inline footnote */
1267
+/*
1268
+** char_footnote -- '(': parsing a standalone inline footnote.
1269
+*/
12351270
static size_t char_footnote(
12361271
struct Blob *ob,
12371272
struct render *rndr,
12381273
char *data,
12391274
size_t offset,
@@ -1251,11 +1286,13 @@
12511286
rndr->make.footnote_ref(ob,0,&fn->upc,fn->iMark,1,rndr->make.opaque);
12521287
}
12531288
return end+1;
12541289
}
12551290
1256
-/* char_link -- '[': parsing a link or an image */
1291
+/*
1292
+** char_link -- '[': parsing a link or an image.
1293
+*/
12571294
static size_t char_link(
12581295
struct Blob *ob,
12591296
struct render *rndr,
12601297
char *data,
12611298
size_t offset,
@@ -1288,11 +1325,11 @@
12881325
fn = &rndr->notes.misref;
12891326
}
12901327
}else{
12911328
12921329
/* skip "inter-bracket-whitespace" - any amount of whitespace or newline */
1293
- /* (this is much more laxist than original markdown syntax) */
1330
+ /* (this is much more lax than original markdown syntax) */
12941331
while( i<size && (data[i]==' ' || data[i]=='\t' || data[i]=='\n') ){ i++; }
12951332
12961333
/* allocate temporary buffers to store content, link and title */
12971334
title = new_work_buffer(rndr);
12981335
content = new_work_buffer(rndr);
@@ -1307,35 +1344,29 @@
13071344
fn = add_inline_footnote(rndr, data+(i+2), k-2);
13081345
i += k+1;
13091346
}else{ /* inline style link */
13101347
size_t span_end = i;
13111348
while( span_end<size
1312
- && !(data[span_end]==')' && (span_end==i || data[span_end-1]!='\\'))
1313
- ){
1349
+ && !(data[span_end]==')'
1350
+ && (span_end==i || data[span_end-1]!='\\')) ){
13141351
span_end++;
13151352
}
1316
-
13171353
if( span_end>=size
1318
- || get_link_inline(link, title, data+i+1, span_end-(i+1))<0
1319
- ){
1354
+ || get_link_inline(link, title, data+i+1, span_end-(i+1))<0 ){
13201355
goto char_link_cleanup;
13211356
}
1322
-
13231357
i = span_end+1;
13241358
}
1325
-
13261359
/* reference style link or span-bounded footnote reference */
13271360
}else if( i<size && data[i]=='[' ){
13281361
char *id_data;
13291362
size_t id_size, id_end = i;
13301363
int bFootnote;
13311364
13321365
while( id_end<size && data[id_end]!=']' ){ id_end++; }
1333
-
13341366
if( id_end>=size ) goto char_link_cleanup;
13351367
bFootnote = data[i+1]=='^';
1336
-
13371368
if( i+1==id_end || (bFootnote && i+2==id_end) ){
13381369
/* implicit id - use the contents */
13391370
id_data = data+1;
13401371
id_size = txt_e-1;
13411372
}else{
@@ -1345,23 +1376,20 @@
13451376
if( bFootnote ){
13461377
id_data++;
13471378
id_size--;
13481379
}
13491380
}
1350
-
13511381
if( bFootnote ){
13521382
fn = get_footnote(rndr, id_data, id_size);
13531383
if( !fn ) {
13541384
rndr->notes.misref.nUsed++;
13551385
fn = &rndr->notes.misref;
13561386
}
13571387
}else if( get_link_ref(rndr, link, title, id_data, id_size)<0 ){
13581388
goto char_link_cleanup;
13591389
}
1360
-
13611390
i = id_end+1;
1362
-
13631391
/* shortcut reference style link */
13641392
}else{
13651393
if( get_link_ref(rndr, link, title, data+1, txt_e-1)<0 ){
13661394
goto char_link_cleanup;
13671395
}
@@ -1375,16 +1403,18 @@
13751403
else parse_inline(content, rndr, data+1, txt_e-1);
13761404
}
13771405
13781406
/* calling the relevant rendering function */
13791407
if( is_img ){
1380
- if( blob_size(ob)>0 && blob_buffer(ob)[blob_size(ob)-1]=='!' ) ob->nUsed--;
1408
+ if( blob_size(ob)>0 && blob_buffer(ob)[blob_size(ob)-1]=='!' ){
1409
+ ob->nUsed--;
1410
+ }
13811411
ret = rndr->make.image(ob, link, title, content, rndr->make.opaque);
1382
- }else if(fn){
1412
+ }else if( fn ){
13831413
if( rndr->make.footnote_ref ){
1384
- ret = rndr->make.footnote_ref(ob, content, &fn->upc, fn->iMark, fn->nUsed,
1385
- rndr->make.opaque);
1414
+ ret = rndr->make.footnote_ref(ob, content, &fn->upc, fn->iMark,
1415
+ fn->nUsed, rndr->make.opaque);
13861416
}
13871417
}else{
13881418
ret = rndr->make.link(ob, link, title, content, rndr->make.opaque);
13891419
}
13901420
@@ -1393,11 +1423,10 @@
13931423
release_work_buffer(rndr, title);
13941424
release_work_buffer(rndr, link);
13951425
release_work_buffer(rndr, content);
13961426
return ret ? i : 0;
13971427
}
1398
-
13991428
14001429
14011430
/*********************************
14021431
* BLOCK-LEVEL PARSING FUNCTIONS *
14031432
*********************************/
@@ -2532,18 +2561,19 @@
25322561
while( indent<end && data[indent]==' ' ){ indent++; }
25332562
if( indent>=end ) goto footnote_finish;
25342563
indent -= i;
25352564
if( indent<2 ) goto footnote_finish;
25362565
2537
- /* process the 2nd and the following lines */
2566
+ /* process the 2nd and subsequent lines */
25382567
while( i+indent<end && memcmp(data+i,spaces,indent)==0 ){
25392568
size_t j;
25402569
i += indent;
25412570
if( !upc_offset ){
25422571
/* a classlist must be provided no later than at the 2nd line */
25432572
upc_offset = i + sizeof_blank_prefix(data+i, end-i, 1);
2544
- upc_size = is_footnote_classlist(data+upc_offset, end-upc_offset, 1);
2573
+ upc_size = is_footnote_classlist(data+upc_offset,
2574
+ end-upc_offset, 1);
25452575
if( upc_size ){
25462576
i = upc_offset + upc_size;
25472577
}
25482578
}
25492579
j = i;
@@ -2599,11 +2629,11 @@
25992629
struct link_ref *lr;
26002630
struct footnote *fn;
26012631
size_t i, beg, end = 0;
26022632
struct render rndr;
26032633
Blob text = BLOB_INITIALIZER; /* input after the first pass */
2604
- Blob *allNotes = &rndr.notes.all;
2634
+ Blob * const allNotes = &rndr.notes.all;
26052635
26062636
/* filling the render structure */
26072637
if( !rndrer ) return;
26082638
rndr.make = *rndrer;
26092639
rndr.nBlobCache = 0;
26102640
--- src/markdown.c
+++ src/markdown.c
@@ -118,11 +118,13 @@
118
119 /**********************
120 * EXPORTED FUNCTIONS *
121 **********************/
122
123 /* markdown -- parses the input buffer and renders it into the output buffer */
 
 
124 void markdown(
125 struct Blob *ob,
126 const struct Blob *ib,
127 const struct mkd_renderer *rndr);
128
@@ -135,18 +137,21 @@
135
136 /***************
137 * LOCAL TYPES *
138 ***************/
139
140 /* link_ref -- reference to a link */
 
 
141 struct link_ref {
142 struct Blob id; /* must be the first field as in footnote struct */
143 struct Blob link;
144 struct Blob title;
145 };
146
147 /* A footnote's data.
 
148 ** id, text, and upc fields must be in that particular order.
149 */
150 struct footnote {
151 struct Blob id; /* must be the first field as in link_ref struct */
152 struct Blob text; /* footnote's content that is rendered at the end */
@@ -216,12 +221,14 @@
216
217 /***************************
218 * STATIC HELPER FUNCTIONS *
219 ***************************/
220
221 /* build_ref_id -- collapse whitespace from input text to make it a ref id */
222 /* TODO: maybe also handle CR+LF line endings? */
 
 
223 static int build_ref_id(struct Blob *id, const char *data, size_t size){
224 size_t beg, i;
225 char *id_data;
226
227 /* skip leading whitespace */
@@ -276,13 +283,15 @@
276 struct link_ref *lra = (void *)a;
277 struct link_ref *lrb = (void *)b;
278 return blob_compare(&lra->id, &lrb->id);
279 }
280
281 /* cmp_footnote_id -- comparison function for footnotes qsort.
282 * Empty IDs sort last (in undetermined order).
283 * Equal IDs are sorted in the order of definition in the source */
 
 
284 static int cmp_footnote_id(const void *fna, const void *fnb){
285 const struct footnote *a = fna, *b = fnb;
286 const int szA = blob_size(&a->id), szB = blob_size(&b->id);
287 if( szA ){
288 if( szB ){
@@ -295,13 +304,15 @@
295 if( a->defno > b->defno ) return 1;
296 assert(!"reachable");
297 return 0; /* should never reach here */
298 }
299
300 /* cmp_footnote_sort -- comparison function for footnotes qsort.
301 * Unreferenced footnotes (when nUsed == 0) sort last and
302 * are sorted in the order of definition in the source */
 
 
303 static int cmp_footnote_sort(const void *fna, const void *fnb){
304 const struct footnote *a = fna, *b = fnb;
305 int i, j;
306 assert( a->nUsed >= 0 );
307 assert( b->nUsed >= 0 );
@@ -652,12 +663,14 @@
652 if( fossil_isalnum(after) ) return 0;
653 return 1;
654 }
655
656
657 /* parse_emph1 -- parsing single emphasis */
658 /* closed by a symbol not preceded by whitespace and not followed by symbol */
 
 
659 static size_t parse_emph1(
660 struct Blob *ob,
661 struct render *rndr,
662 char *data,
663 size_t size,
@@ -697,12 +710,13 @@
697 }
698 }
699 return 0;
700 }
701
702
703 /* parse_emph2 -- parsing single emphasis */
 
704 static size_t parse_emph2(
705 struct Blob *ob,
706 struct render *rndr,
707 char *data,
708 size_t size,
@@ -736,13 +750,14 @@
736 i++;
737 }
738 return 0;
739 }
740
741
742 /* parse_emph3 -- parsing single emphasis */
743 /* finds the first closing tag, and delegates to the other emph */
 
744 static size_t parse_emph3(
745 struct Blob *ob,
746 struct render *rndr,
747 char *data,
748 size_t size,
@@ -784,12 +799,13 @@
784 }
785 }
786 return 0;
787 }
788
789
790 /* char_emphasis -- single and double emphasis parsing */
 
791 static size_t char_emphasis(
792 struct Blob *ob,
793 struct render *rndr,
794 char *data,
795 size_t offset,
@@ -829,12 +845,13 @@
829 return ret+3;
830 }
831 return 0;
832 }
833
834
835 /* char_linebreak -- '\n' preceded by two spaces (assuming linebreak != 0) */
 
836 static size_t char_linebreak(
837 struct Blob *ob,
838 struct render *rndr,
839 char *data,
840 size_t offset,
@@ -844,12 +861,13 @@
844 /* removing the last space from ob and rendering */
845 if( blob_size(ob)>0 && blob_buffer(ob)[blob_size(ob)-1]==' ' ) ob->nUsed--;
846 return rndr->make.linebreak(ob, rndr->make.opaque) ? 1 : 0;
847 }
848
849
850 /* char_codespan -- '`' parsing a code span (assuming codespan != 0) */
 
851 static size_t char_codespan(
852 struct Blob *ob,
853 struct render *rndr,
854 char *data,
855 size_t offset,
@@ -886,11 +904,13 @@
886 }
887 return end;
888 }
889
890
891 /* char_escape -- '\\' backslash escape */
 
 
892 static size_t char_escape(
893 struct Blob *ob,
894 struct render *rndr,
895 char *data,
896 size_t offset,
@@ -906,13 +926,14 @@
906 }
907 }
908 return 2;
909 }
910
911
912 /* char_entity -- '&' escaped when it doesn't belong to an entity */
913 /* valid entities are assumed to be anything matching &#?[A-Za-z0-9]+; */
 
914 static size_t char_entity(
915 struct Blob *ob,
916 struct render *rndr,
917 char *data,
918 size_t offset,
@@ -942,12 +963,13 @@
942 blob_append(ob, data, end);
943 }
944 return end;
945 }
946
947
948 /* char_langle_tag -- '<' when tags or autolinks are allowed */
 
949 static size_t char_langle_tag(
950 struct Blob *ob,
951 struct render *rndr,
952 char *data,
953 size_t offset,
@@ -972,12 +994,12 @@
972 }else{
973 return end;
974 }
975 }
976
977
978 /* get_link_inline -- extract inline-style link and title from
979 ** parenthesed data
980 */
981 static int get_link_inline(
982 struct Blob *link,
983 struct Blob *title,
@@ -1048,11 +1070,13 @@
1048 /* this function always succeed */
1049 return 0;
1050 }
1051
1052
1053 /* get_link_ref -- extract referenced link and title from id */
 
 
1054 static int get_link_ref(
1055 struct render *rndr,
1056 struct Blob *link,
1057 struct Blob *title,
1058 char *data,
@@ -1076,13 +1100,15 @@
1076 blob_appendb(link, &lr->link);
1077 blob_appendb(title, &lr->title);
1078 return 0;
1079 }
1080
1081 /* get_footnote() -- find a footnote by label, invoked during the 2nd pass.
1082 * On success returns a footnote (after incrementing its nUsed field),
1083 * otherwise returns NULL */
 
 
1084 static const struct footnote* get_footnote(
1085 struct render *rndr,
1086 const char *data,
1087 size_t size
1088 ){
@@ -1105,14 +1131,15 @@
1105 cleanup:
1106 release_work_buffer( rndr, id );
1107 return fn;
1108 }
1109
1110 /* Counts characters in the blank prefix within at most nHalfLines.
 
1111 ** A sequence of spaces and tabs counts as odd halfline,
1112 ** a newline counts as even halfline.
1113 ** If nHalfLines < 0 then procceed without constrains.
1114 */
1115 static inline size_t sizeof_blank_prefix(
1116 const char *data, size_t size, int nHalfLines
1117 ){
1118 const char *p = data;
@@ -1134,22 +1161,24 @@
1134 nHalfLines--;
1135 }
1136 return p-data;
1137 }
1138
1139 /* Check if the data starts with a classlist token of the special form.
 
1140 ** If so then return the length of that token, otherwise return 0.
1141 **
1142 ** The token must start with a dot and must end with a colon;
1143 ** in between of these it must be a dot-separated list of words;
1144 ** each word may contain only alphanumeric characters and hyphens.
1145 **
1146 ** If `bBlank` is non-zero then a blank character must follow
1147 ** the token's ending colon: otherwise function returns 0
1148 ** despite of the well-formed token.
1149 */
1150 size_t is_footnote_classlist(const char * const data, size_t size, int bBlank){
 
1151 const char *p;
1152 const char * const end = data+size;
1153 if( data==end || *data != '.' ) return 0;
1154 for(p=data+1; p!=end; p++){
1155 if( fossil_isalnum(*p) || *p=='-' ) continue;
@@ -1164,13 +1193,16 @@
1164 if( *p!='.' ) break;
1165 }
1166 return 0;
1167 }
1168
1169 /* Adds unlabeled footnote to the rndr.
1170 * If text is blank then returns 0,
1171 * otherwise returns the address of the added footnote. */
 
 
 
1172 static inline const struct footnote* add_inline_footnote(
1173 struct render *rndr,
1174 const char *text,
1175 size_t size
1176 ){
@@ -1202,12 +1234,13 @@
1202 blob_append(&rndr->notes.all, (char *)&fn, sizeof fn);
1203 return (struct footnote*)( blob_buffer(&rndr->notes.all)
1204 +( blob_size(&rndr->notes.all)-sizeof fn ));
1205 }
1206
1207 /* Return the offset of the matching closing bracket or 0 if not found.
1208 ** begin[0] must be either '[' or '('
 
1209 **
1210 ** TODO: It seems that things like "\\(" are not handled correctly.
1211 ** That is historical behavior for a corner-case,
1212 ** so it's left as it is until somebody complains.
1213 */
@@ -1229,11 +1262,13 @@
1229 }
1230 }
1231 return 0;
1232 }
1233
1234 /* char_footnote -- '(': parsing a standalone inline footnote */
 
 
1235 static size_t char_footnote(
1236 struct Blob *ob,
1237 struct render *rndr,
1238 char *data,
1239 size_t offset,
@@ -1251,11 +1286,13 @@
1251 rndr->make.footnote_ref(ob,0,&fn->upc,fn->iMark,1,rndr->make.opaque);
1252 }
1253 return end+1;
1254 }
1255
1256 /* char_link -- '[': parsing a link or an image */
 
 
1257 static size_t char_link(
1258 struct Blob *ob,
1259 struct render *rndr,
1260 char *data,
1261 size_t offset,
@@ -1288,11 +1325,11 @@
1288 fn = &rndr->notes.misref;
1289 }
1290 }else{
1291
1292 /* skip "inter-bracket-whitespace" - any amount of whitespace or newline */
1293 /* (this is much more laxist than original markdown syntax) */
1294 while( i<size && (data[i]==' ' || data[i]=='\t' || data[i]=='\n') ){ i++; }
1295
1296 /* allocate temporary buffers to store content, link and title */
1297 title = new_work_buffer(rndr);
1298 content = new_work_buffer(rndr);
@@ -1307,35 +1344,29 @@
1307 fn = add_inline_footnote(rndr, data+(i+2), k-2);
1308 i += k+1;
1309 }else{ /* inline style link */
1310 size_t span_end = i;
1311 while( span_end<size
1312 && !(data[span_end]==')' && (span_end==i || data[span_end-1]!='\\'))
1313 ){
1314 span_end++;
1315 }
1316
1317 if( span_end>=size
1318 || get_link_inline(link, title, data+i+1, span_end-(i+1))<0
1319 ){
1320 goto char_link_cleanup;
1321 }
1322
1323 i = span_end+1;
1324 }
1325
1326 /* reference style link or span-bounded footnote reference */
1327 }else if( i<size && data[i]=='[' ){
1328 char *id_data;
1329 size_t id_size, id_end = i;
1330 int bFootnote;
1331
1332 while( id_end<size && data[id_end]!=']' ){ id_end++; }
1333
1334 if( id_end>=size ) goto char_link_cleanup;
1335 bFootnote = data[i+1]=='^';
1336
1337 if( i+1==id_end || (bFootnote && i+2==id_end) ){
1338 /* implicit id - use the contents */
1339 id_data = data+1;
1340 id_size = txt_e-1;
1341 }else{
@@ -1345,23 +1376,20 @@
1345 if( bFootnote ){
1346 id_data++;
1347 id_size--;
1348 }
1349 }
1350
1351 if( bFootnote ){
1352 fn = get_footnote(rndr, id_data, id_size);
1353 if( !fn ) {
1354 rndr->notes.misref.nUsed++;
1355 fn = &rndr->notes.misref;
1356 }
1357 }else if( get_link_ref(rndr, link, title, id_data, id_size)<0 ){
1358 goto char_link_cleanup;
1359 }
1360
1361 i = id_end+1;
1362
1363 /* shortcut reference style link */
1364 }else{
1365 if( get_link_ref(rndr, link, title, data+1, txt_e-1)<0 ){
1366 goto char_link_cleanup;
1367 }
@@ -1375,16 +1403,18 @@
1375 else parse_inline(content, rndr, data+1, txt_e-1);
1376 }
1377
1378 /* calling the relevant rendering function */
1379 if( is_img ){
1380 if( blob_size(ob)>0 && blob_buffer(ob)[blob_size(ob)-1]=='!' ) ob->nUsed--;
 
 
1381 ret = rndr->make.image(ob, link, title, content, rndr->make.opaque);
1382 }else if(fn){
1383 if( rndr->make.footnote_ref ){
1384 ret = rndr->make.footnote_ref(ob, content, &fn->upc, fn->iMark, fn->nUsed,
1385 rndr->make.opaque);
1386 }
1387 }else{
1388 ret = rndr->make.link(ob, link, title, content, rndr->make.opaque);
1389 }
1390
@@ -1393,11 +1423,10 @@
1393 release_work_buffer(rndr, title);
1394 release_work_buffer(rndr, link);
1395 release_work_buffer(rndr, content);
1396 return ret ? i : 0;
1397 }
1398
1399
1400
1401 /*********************************
1402 * BLOCK-LEVEL PARSING FUNCTIONS *
1403 *********************************/
@@ -2532,18 +2561,19 @@
2532 while( indent<end && data[indent]==' ' ){ indent++; }
2533 if( indent>=end ) goto footnote_finish;
2534 indent -= i;
2535 if( indent<2 ) goto footnote_finish;
2536
2537 /* process the 2nd and the following lines */
2538 while( i+indent<end && memcmp(data+i,spaces,indent)==0 ){
2539 size_t j;
2540 i += indent;
2541 if( !upc_offset ){
2542 /* a classlist must be provided no later than at the 2nd line */
2543 upc_offset = i + sizeof_blank_prefix(data+i, end-i, 1);
2544 upc_size = is_footnote_classlist(data+upc_offset, end-upc_offset, 1);
 
2545 if( upc_size ){
2546 i = upc_offset + upc_size;
2547 }
2548 }
2549 j = i;
@@ -2599,11 +2629,11 @@
2599 struct link_ref *lr;
2600 struct footnote *fn;
2601 size_t i, beg, end = 0;
2602 struct render rndr;
2603 Blob text = BLOB_INITIALIZER; /* input after the first pass */
2604 Blob *allNotes = &rndr.notes.all;
2605
2606 /* filling the render structure */
2607 if( !rndrer ) return;
2608 rndr.make = *rndrer;
2609 rndr.nBlobCache = 0;
2610
--- src/markdown.c
+++ src/markdown.c
@@ -118,11 +118,13 @@
118
119 /**********************
120 * EXPORTED FUNCTIONS *
121 **********************/
122
123 /*
124 ** markdown -- parses the input buffer and renders it into the output buffer.
125 */
126 void markdown(
127 struct Blob *ob,
128 const struct Blob *ib,
129 const struct mkd_renderer *rndr);
130
@@ -135,18 +137,21 @@
137
138 /***************
139 * LOCAL TYPES *
140 ***************/
141
142 /*
143 ** link_ref -- reference to a link.
144 */
145 struct link_ref {
146 struct Blob id; /* must be the first field as in footnote struct */
147 struct Blob link;
148 struct Blob title;
149 };
150
151 /*
152 ** A footnote's data.
153 ** id, text, and upc fields must be in that particular order.
154 */
155 struct footnote {
156 struct Blob id; /* must be the first field as in link_ref struct */
157 struct Blob text; /* footnote's content that is rendered at the end */
@@ -216,12 +221,14 @@
221
222 /***************************
223 * STATIC HELPER FUNCTIONS *
224 ***************************/
225
226 /*
227 ** build_ref_id -- collapse whitespace from input text to make it a ref id.
228 ** Potential TODO: maybe also handle CR+LF line endings?
229 */
230 static int build_ref_id(struct Blob *id, const char *data, size_t size){
231 size_t beg, i;
232 char *id_data;
233
234 /* skip leading whitespace */
@@ -276,13 +283,15 @@
283 struct link_ref *lra = (void *)a;
284 struct link_ref *lrb = (void *)b;
285 return blob_compare(&lra->id, &lrb->id);
286 }
287
288 /*
289 ** cmp_footnote_id -- comparison function for footnotes qsort.
290 ** Empty IDs sort last (in undetermined order).
291 ** Equal IDs are sorted in the order of definition in the source.
292 */
293 static int cmp_footnote_id(const void *fna, const void *fnb){
294 const struct footnote *a = fna, *b = fnb;
295 const int szA = blob_size(&a->id), szB = blob_size(&b->id);
296 if( szA ){
297 if( szB ){
@@ -295,13 +304,15 @@
304 if( a->defno > b->defno ) return 1;
305 assert(!"reachable");
306 return 0; /* should never reach here */
307 }
308
309 /*
310 ** cmp_footnote_sort -- comparison function for footnotes qsort.
311 ** Unreferenced footnotes (when nUsed == 0) sort last and
312 ** are sorted in the order of definition in the source.
313 */
314 static int cmp_footnote_sort(const void *fna, const void *fnb){
315 const struct footnote *a = fna, *b = fnb;
316 int i, j;
317 assert( a->nUsed >= 0 );
318 assert( b->nUsed >= 0 );
@@ -652,12 +663,14 @@
663 if( fossil_isalnum(after) ) return 0;
664 return 1;
665 }
666
667
668 /*
669 ** parse_emph1 -- parsing single emphasis.
670 ** closed by a symbol not preceded by whitespace and not followed by symbol.
671 */
672 static size_t parse_emph1(
673 struct Blob *ob,
674 struct render *rndr,
675 char *data,
676 size_t size,
@@ -697,12 +710,13 @@
710 }
711 }
712 return 0;
713 }
714
715 /*
716 ** parse_emph2 -- parsing single emphasis.
717 */
718 static size_t parse_emph2(
719 struct Blob *ob,
720 struct render *rndr,
721 char *data,
722 size_t size,
@@ -736,13 +750,14 @@
750 i++;
751 }
752 return 0;
753 }
754
755 /*
756 ** parse_emph3 -- parsing single emphasis.
757 ** finds the first closing tag, and delegates to the other emph.
758 */
759 static size_t parse_emph3(
760 struct Blob *ob,
761 struct render *rndr,
762 char *data,
763 size_t size,
@@ -784,12 +799,13 @@
799 }
800 }
801 return 0;
802 }
803
804 /*
805 ** char_emphasis -- single and double emphasis parsing.
806 */
807 static size_t char_emphasis(
808 struct Blob *ob,
809 struct render *rndr,
810 char *data,
811 size_t offset,
@@ -829,12 +845,13 @@
845 return ret+3;
846 }
847 return 0;
848 }
849
850 /*
851 ** char_linebreak -- '\n' preceded by two spaces (assuming linebreak != 0).
852 */
853 static size_t char_linebreak(
854 struct Blob *ob,
855 struct render *rndr,
856 char *data,
857 size_t offset,
@@ -844,12 +861,13 @@
861 /* removing the last space from ob and rendering */
862 if( blob_size(ob)>0 && blob_buffer(ob)[blob_size(ob)-1]==' ' ) ob->nUsed--;
863 return rndr->make.linebreak(ob, rndr->make.opaque) ? 1 : 0;
864 }
865
866 /*
867 ** char_codespan -- '`' parsing a code span (assuming codespan != 0).
868 */
869 static size_t char_codespan(
870 struct Blob *ob,
871 struct render *rndr,
872 char *data,
873 size_t offset,
@@ -886,11 +904,13 @@
904 }
905 return end;
906 }
907
908
909 /*
910 ** char_escape -- '\\' backslash escape.
911 */
912 static size_t char_escape(
913 struct Blob *ob,
914 struct render *rndr,
915 char *data,
916 size_t offset,
@@ -906,13 +926,14 @@
926 }
927 }
928 return 2;
929 }
930
931 /*
932 ** char_entity -- '&' escaped when it doesn't belong to an entity.
933 ** valid entities are assumed to be anything matching &#?[A-Za-z0-9]+;
934 */
935 static size_t char_entity(
936 struct Blob *ob,
937 struct render *rndr,
938 char *data,
939 size_t offset,
@@ -942,12 +963,13 @@
963 blob_append(ob, data, end);
964 }
965 return end;
966 }
967
968 /*
969 ** char_langle_tag -- '<' when tags or autolinks are allowed.
970 */
971 static size_t char_langle_tag(
972 struct Blob *ob,
973 struct render *rndr,
974 char *data,
975 size_t offset,
@@ -972,12 +994,12 @@
994 }else{
995 return end;
996 }
997 }
998
999 /*
1000 ** get_link_inline -- extract inline-style link and title from
1001 ** parenthesed data
1002 */
1003 static int get_link_inline(
1004 struct Blob *link,
1005 struct Blob *title,
@@ -1048,11 +1070,13 @@
1070 /* this function always succeed */
1071 return 0;
1072 }
1073
1074
1075 /*
1076 ** get_link_ref -- extract referenced link and title from id.
1077 */
1078 static int get_link_ref(
1079 struct render *rndr,
1080 struct Blob *link,
1081 struct Blob *title,
1082 char *data,
@@ -1076,13 +1100,15 @@
1100 blob_appendb(link, &lr->link);
1101 blob_appendb(title, &lr->title);
1102 return 0;
1103 }
1104
1105 /*
1106 ** get_footnote() -- find a footnote by label, invoked during the 2nd pass.
1107 ** On success returns a footnote (after incrementing its nUsed field),
1108 ** otherwise returns NULL.
1109 */
1110 static const struct footnote* get_footnote(
1111 struct render *rndr,
1112 const char *data,
1113 size_t size
1114 ){
@@ -1105,14 +1131,15 @@
1131 cleanup:
1132 release_work_buffer( rndr, id );
1133 return fn;
1134 }
1135
1136 /*
1137 ** Counts characters in the blank prefix within at most nHalfLines.
1138 ** A sequence of spaces and tabs counts as odd halfline,
1139 ** a newline counts as even halfline.
1140 ** If nHalfLines < 0 then proceed without constraints.
1141 */
1142 static inline size_t sizeof_blank_prefix(
1143 const char *data, size_t size, int nHalfLines
1144 ){
1145 const char *p = data;
@@ -1134,22 +1161,24 @@
1161 nHalfLines--;
1162 }
1163 return p-data;
1164 }
1165
1166 /*
1167 ** Check if the data starts with a classlist token of the special form.
1168 ** If so then return the length of that token, otherwise return 0.
1169 **
1170 ** The token must start with a dot and must end with a colon;
1171 ** in between of these it must be a dot-separated list of words;
1172 ** each word may contain only alphanumeric characters and hyphens.
1173 **
1174 ** If `bBlank` is non-zero then a blank character must follow
1175 ** the token's ending colon: otherwise function returns 0
1176 ** despite the well-formed token.
1177 */
1178 static size_t is_footnote_classlist(const char * const data, size_t size,
1179 int bBlank){
1180 const char *p;
1181 const char * const end = data+size;
1182 if( data==end || *data != '.' ) return 0;
1183 for(p=data+1; p!=end; p++){
1184 if( fossil_isalnum(*p) || *p=='-' ) continue;
@@ -1164,13 +1193,16 @@
1193 if( *p!='.' ) break;
1194 }
1195 return 0;
1196 }
1197
1198 /*
1199 ** Adds unlabeled footnote to the rndr. If text is blank then returns
1200 ** 0, otherwise returns the address of the added footnote, which lives
1201 ** in rndr->notes, noting that the pointer may be invalidated via
1202 ** reallocation the next time a footnote is added to that member.
1203 */
1204 static inline const struct footnote* add_inline_footnote(
1205 struct render *rndr,
1206 const char *text,
1207 size_t size
1208 ){
@@ -1202,12 +1234,13 @@
1234 blob_append(&rndr->notes.all, (char *)&fn, sizeof fn);
1235 return (struct footnote*)( blob_buffer(&rndr->notes.all)
1236 +( blob_size(&rndr->notes.all)-sizeof fn ));
1237 }
1238
1239 /*
1240 ** Return the byte offset of the matching closing bracket or 0 if not
1241 ** found. begin[0] must be either '[' or '('.
1242 **
1243 ** TODO: It seems that things like "\\(" are not handled correctly.
1244 ** That is historical behavior for a corner-case,
1245 ** so it's left as it is until somebody complains.
1246 */
@@ -1229,11 +1262,13 @@
1262 }
1263 }
1264 return 0;
1265 }
1266
1267 /*
1268 ** char_footnote -- '(': parsing a standalone inline footnote.
1269 */
1270 static size_t char_footnote(
1271 struct Blob *ob,
1272 struct render *rndr,
1273 char *data,
1274 size_t offset,
@@ -1251,11 +1286,13 @@
1286 rndr->make.footnote_ref(ob,0,&fn->upc,fn->iMark,1,rndr->make.opaque);
1287 }
1288 return end+1;
1289 }
1290
1291 /*
1292 ** char_link -- '[': parsing a link or an image.
1293 */
1294 static size_t char_link(
1295 struct Blob *ob,
1296 struct render *rndr,
1297 char *data,
1298 size_t offset,
@@ -1288,11 +1325,11 @@
1325 fn = &rndr->notes.misref;
1326 }
1327 }else{
1328
1329 /* skip "inter-bracket-whitespace" - any amount of whitespace or newline */
1330 /* (this is much more lax than original markdown syntax) */
1331 while( i<size && (data[i]==' ' || data[i]=='\t' || data[i]=='\n') ){ i++; }
1332
1333 /* allocate temporary buffers to store content, link and title */
1334 title = new_work_buffer(rndr);
1335 content = new_work_buffer(rndr);
@@ -1307,35 +1344,29 @@
1344 fn = add_inline_footnote(rndr, data+(i+2), k-2);
1345 i += k+1;
1346 }else{ /* inline style link */
1347 size_t span_end = i;
1348 while( span_end<size
1349 && !(data[span_end]==')'
1350 && (span_end==i || data[span_end-1]!='\\')) ){
1351 span_end++;
1352 }
 
1353 if( span_end>=size
1354 || get_link_inline(link, title, data+i+1, span_end-(i+1))<0 ){
 
1355 goto char_link_cleanup;
1356 }
 
1357 i = span_end+1;
1358 }
 
1359 /* reference style link or span-bounded footnote reference */
1360 }else if( i<size && data[i]=='[' ){
1361 char *id_data;
1362 size_t id_size, id_end = i;
1363 int bFootnote;
1364
1365 while( id_end<size && data[id_end]!=']' ){ id_end++; }
 
1366 if( id_end>=size ) goto char_link_cleanup;
1367 bFootnote = data[i+1]=='^';
 
1368 if( i+1==id_end || (bFootnote && i+2==id_end) ){
1369 /* implicit id - use the contents */
1370 id_data = data+1;
1371 id_size = txt_e-1;
1372 }else{
@@ -1345,23 +1376,20 @@
1376 if( bFootnote ){
1377 id_data++;
1378 id_size--;
1379 }
1380 }
 
1381 if( bFootnote ){
1382 fn = get_footnote(rndr, id_data, id_size);
1383 if( !fn ) {
1384 rndr->notes.misref.nUsed++;
1385 fn = &rndr->notes.misref;
1386 }
1387 }else if( get_link_ref(rndr, link, title, id_data, id_size)<0 ){
1388 goto char_link_cleanup;
1389 }
 
1390 i = id_end+1;
 
1391 /* shortcut reference style link */
1392 }else{
1393 if( get_link_ref(rndr, link, title, data+1, txt_e-1)<0 ){
1394 goto char_link_cleanup;
1395 }
@@ -1375,16 +1403,18 @@
1403 else parse_inline(content, rndr, data+1, txt_e-1);
1404 }
1405
1406 /* calling the relevant rendering function */
1407 if( is_img ){
1408 if( blob_size(ob)>0 && blob_buffer(ob)[blob_size(ob)-1]=='!' ){
1409 ob->nUsed--;
1410 }
1411 ret = rndr->make.image(ob, link, title, content, rndr->make.opaque);
1412 }else if( fn ){
1413 if( rndr->make.footnote_ref ){
1414 ret = rndr->make.footnote_ref(ob, content, &fn->upc, fn->iMark,
1415 fn->nUsed, rndr->make.opaque);
1416 }
1417 }else{
1418 ret = rndr->make.link(ob, link, title, content, rndr->make.opaque);
1419 }
1420
@@ -1393,11 +1423,10 @@
1423 release_work_buffer(rndr, title);
1424 release_work_buffer(rndr, link);
1425 release_work_buffer(rndr, content);
1426 return ret ? i : 0;
1427 }
 
1428
1429
1430 /*********************************
1431 * BLOCK-LEVEL PARSING FUNCTIONS *
1432 *********************************/
@@ -2532,18 +2561,19 @@
2561 while( indent<end && data[indent]==' ' ){ indent++; }
2562 if( indent>=end ) goto footnote_finish;
2563 indent -= i;
2564 if( indent<2 ) goto footnote_finish;
2565
2566 /* process the 2nd and subsequent lines */
2567 while( i+indent<end && memcmp(data+i,spaces,indent)==0 ){
2568 size_t j;
2569 i += indent;
2570 if( !upc_offset ){
2571 /* a classlist must be provided no later than at the 2nd line */
2572 upc_offset = i + sizeof_blank_prefix(data+i, end-i, 1);
2573 upc_size = is_footnote_classlist(data+upc_offset,
2574 end-upc_offset, 1);
2575 if( upc_size ){
2576 i = upc_offset + upc_size;
2577 }
2578 }
2579 j = i;
@@ -2599,11 +2629,11 @@
2629 struct link_ref *lr;
2630 struct footnote *fn;
2631 size_t i, beg, end = 0;
2632 struct render rndr;
2633 Blob text = BLOB_INITIALIZER; /* input after the first pass */
2634 Blob * const allNotes = &rndr.notes.all;
2635
2636 /* filling the render structure */
2637 if( !rndrer ) return;
2638 rndr.make = *rndrer;
2639 rndr.nBlobCache = 0;
2640
+1 -1
--- src/markdown.md
+++ src/markdown.md
@@ -180,11 +180,11 @@
180180
> ```
181181
> [^label]: Footnote definition must start on the first column.
182182
> The second line (if any) must be indented by two or more spaces.
183183
> Definition continues until indentation drops below that of the 2nd line.
184184
>```
185
-> Charachter **^** is not part of a label, it is part of the syntax.
185
+> Character **^** is not part of a label, it is part of the syntax.
186186
> Both a footnote's text and a fragment to which a footnote applies
187187
> are subject to further interpretation as Markdown sources.
188188
189189
## Miscellaneous ##
190190
191191
--- src/markdown.md
+++ src/markdown.md
@@ -180,11 +180,11 @@
180 > ```
181 > [^label]: Footnote definition must start on the first column.
182 > The second line (if any) must be indented by two or more spaces.
183 > Definition continues until indentation drops below that of the 2nd line.
184 >```
185 > Charachter **^** is not part of a label, it is part of the syntax.
186 > Both a footnote's text and a fragment to which a footnote applies
187 > are subject to further interpretation as Markdown sources.
188
189 ## Miscellaneous ##
190
191
--- src/markdown.md
+++ src/markdown.md
@@ -180,11 +180,11 @@
180 > ```
181 > [^label]: Footnote definition must start on the first column.
182 > The second line (if any) must be indented by two or more spaces.
183 > Definition continues until indentation drops below that of the 2nd line.
184 >```
185 > Character **^** is not part of a label, it is part of the syntax.
186 > Both a footnote's text and a fragment to which a footnote applies
187 > are subject to further interpretation as Markdown sources.
188
189 ## Miscellaneous ##
190
191
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -29,11 +29,19 @@
2929
struct Blob *output_title,
3030
struct Blob *output_body);
3131
3232
#endif /* INTERFACE */
3333
34
-typedef union { uint64_t u; char c[8]; unsigned char b[8]; } bitfield64_t;
34
+/*
35
+** Markdown-internal helper for generating unique link reference IDs.
36
+*/
37
+typedef union bitfield64_t bitfield64_t;
38
+union bitfield64_t{
39
+ uint64_t u;
40
+ char c[8];
41
+ unsigned char b[8];
42
+};
3543
3644
/*
3745
** An instance of the following structure is passed through the
3846
** "opaque" pointer.
3947
*/
@@ -50,20 +58,10 @@
5058
5159
/* INTER_BLOCK -- skip a line between block level elements */
5260
#define INTER_BLOCK(ob) \
5361
do { if( blob_size(ob)>0 ) blob_append_char(ob, '\n'); } while (0)
5462
55
-/* BLOB_APPEND_LITERAL -- append a string literal to a blob
56
-** TODO: Refactor all invocations to use global macro blob_append_literal()
57
-*/
58
-#define BLOB_APPEND_LITERAL blob_append_literal
59
-
60
-/* BLOB_APPEND_BLOB -- append blob contents to another
61
-** TODO: Refactor all invocations to use global macro blob_appendb()
62
-*/
63
-#define BLOB_APPEND_BLOB(dest, src) blob_appendb((dest), (src))
64
-
6563
#ifndef FOOTNOTES_WITHOUT_URI
6664
#define BLOB_APPEND_URI(dest,ctx) blob_appendb(dest,&((ctx)->reqURI))
6765
#else
6866
#define BLOB_APPEND_URI(dest,ctx)
6967
#endif
@@ -106,19 +104,19 @@
106104
i++;
107105
}
108106
blob_append(ob, data+beg, i-beg);
109107
while( i<size ){
110108
if( data[i]=='<' ){
111
- BLOB_APPEND_LITERAL(ob, "&lt;");
109
+ blob_append_literal(ob, "&lt;");
112110
}else if( data[i]=='>' ){
113
- BLOB_APPEND_LITERAL(ob, "&gt;");
111
+ blob_append_literal(ob, "&gt;");
114112
}else if( data[i]=='&' ){
115
- BLOB_APPEND_LITERAL(ob, "&amp;");
113
+ blob_append_literal(ob, "&amp;");
116114
}else if( data[i]=='"' ){
117
- BLOB_APPEND_LITERAL(ob, "&quot;");
115
+ blob_append_literal(ob, "&quot;");
118116
}else if( data[i]=='\'' ){
119
- BLOB_APPEND_LITERAL(ob, "&#39;");
117
+ blob_append_literal(ob, "&#39;");
120118
}else{
121119
break;
122120
}
123121
i++;
124122
}
@@ -136,15 +134,15 @@
136134
i++;
137135
}
138136
blob_append(ob, data+beg, i-beg);
139137
while( i<size ){
140138
if( data[i]=='<' ){
141
- BLOB_APPEND_LITERAL(ob, "&lt;");
139
+ blob_append_literal(ob, "&lt;");
142140
}else if( data[i]=='>' ){
143
- BLOB_APPEND_LITERAL(ob, "&gt;");
141
+ blob_append_literal(ob, "&gt;");
144142
}else if( data[i]=='&' ){
145
- BLOB_APPEND_LITERAL(ob, "&amp;");
143
+ blob_append_literal(ob, "&amp;");
146144
}else{
147145
break;
148146
}
149147
i++;
150148
}
@@ -157,17 +155,17 @@
157155
/* Size of the prolog: "<div class='markdown'>\n" */
158156
#define PROLOG_SIZE 23
159157
160158
static void html_prolog(struct Blob *ob, void *opaque){
161159
INTER_BLOCK(ob);
162
- BLOB_APPEND_LITERAL(ob, "<div class=\"markdown\">\n");
160
+ blob_append_literal(ob, "<div class=\"markdown\">\n");
163161
assert( blob_size(ob)==PROLOG_SIZE );
164162
}
165163
166164
static void html_epilog(struct Blob *ob, void *opaque){
167165
INTER_BLOCK(ob);
168
- BLOB_APPEND_LITERAL(ob, "</div>\n");
166
+ blob_append_literal(ob, "</div>\n");
169167
}
170168
171169
static void html_blockhtml(struct Blob *ob, struct Blob *text, void *opaque){
172170
char *data = blob_buffer(text);
173171
size_t size = blob_size(text);
@@ -185,25 +183,25 @@
185183
blob_append(title, data+nTag, size - nTag - 5);
186184
return;
187185
}
188186
INTER_BLOCK(ob);
189187
blob_append(ob, data, size);
190
- BLOB_APPEND_LITERAL(ob, "\n");
188
+ blob_append_literal(ob, "\n");
191189
}
192190
193191
static void html_blockcode(struct Blob *ob, struct Blob *text, void *opaque){
194192
INTER_BLOCK(ob);
195
- BLOB_APPEND_LITERAL(ob, "<pre><code>");
193
+ blob_append_literal(ob, "<pre><code>");
196194
html_escape(ob, blob_buffer(text), blob_size(text));
197
- BLOB_APPEND_LITERAL(ob, "</code></pre>\n");
195
+ blob_append_literal(ob, "</code></pre>\n");
198196
}
199197
200198
static void html_blockquote(struct Blob *ob, struct Blob *text, void *opaque){
201199
INTER_BLOCK(ob);
202
- BLOB_APPEND_LITERAL(ob, "<blockquote>\n");
203
- BLOB_APPEND_BLOB(ob, text);
204
- BLOB_APPEND_LITERAL(ob, "</blockquote>\n");
200
+ blob_append_literal(ob, "<blockquote>\n");
201
+ blob_appendb(ob, text);
202
+ blob_append_literal(ob, "</blockquote>\n");
205203
}
206204
207205
static void html_header(
208206
struct Blob *ob,
209207
struct Blob *text,
@@ -212,22 +210,22 @@
212210
){
213211
struct Blob *title = ((MarkdownToHtml*)opaque)->output_title;
214212
/* The first header at the beginning of a text is considered as
215213
* a title and not output. */
216214
if( blob_size(ob)<=PROLOG_SIZE && title!=0 && blob_size(title)==0 ){
217
- BLOB_APPEND_BLOB(title, text);
215
+ blob_appendb(title, text);
218216
return;
219217
}
220218
INTER_BLOCK(ob);
221219
blob_appendf(ob, "<h%d>", level);
222
- BLOB_APPEND_BLOB(ob, text);
220
+ blob_appendb(ob, text);
223221
blob_appendf(ob, "</h%d>", level);
224222
}
225223
226224
static void html_hrule(struct Blob *ob, void *opaque){
227225
INTER_BLOCK(ob);
228
- BLOB_APPEND_LITERAL(ob, "<hr />\n");
226
+ blob_append_literal(ob, "<hr />\n");
229227
}
230228
231229
232230
static void html_list(
233231
struct Blob *ob,
@@ -238,11 +236,11 @@
238236
char ol[] = "ol";
239237
char ul[] = "ul";
240238
char *tag = (flags & MKD_LIST_ORDERED) ? ol : ul;
241239
INTER_BLOCK(ob);
242240
blob_appendf(ob, "<%s>\n", tag);
243
- BLOB_APPEND_BLOB(ob, text);
241
+ blob_appendb(ob, text);
244242
blob_appendf(ob, "</%s>\n", tag);
245243
}
246244
247245
static void html_list_item(
248246
struct Blob *ob,
@@ -251,20 +249,20 @@
251249
void *opaque
252250
){
253251
char *text_data = blob_buffer(text);
254252
size_t text_size = blob_size(text);
255253
while( text_size>0 && text_data[text_size-1]=='\n' ) text_size--;
256
- BLOB_APPEND_LITERAL(ob, "<li>");
254
+ blob_append_literal(ob, "<li>");
257255
blob_append(ob, text_data, text_size);
258
- BLOB_APPEND_LITERAL(ob, "</li>\n");
256
+ blob_append_literal(ob, "</li>\n");
259257
}
260258
261259
static void html_paragraph(struct Blob *ob, struct Blob *text, void *opaque){
262260
INTER_BLOCK(ob);
263
- BLOB_APPEND_LITERAL(ob, "<p>");
264
- BLOB_APPEND_BLOB(ob, text);
265
- BLOB_APPEND_LITERAL(ob, "</p>\n");
261
+ blob_append_literal(ob, "<p>");
262
+ blob_appendb(ob, text);
263
+ blob_append_literal(ob, "</p>\n");
266264
}
267265
268266
269267
static void html_table(
270268
struct Blob *ob,
@@ -271,84 +269,85 @@
271269
struct Blob *head_row,
272270
struct Blob *rows,
273271
void *opaque
274272
){
275273
INTER_BLOCK(ob);
276
- BLOB_APPEND_LITERAL(ob, "<table>\n");
274
+ blob_append_literal(ob, "<table>\n");
277275
if( head_row && blob_size(head_row)>0 ){
278
- BLOB_APPEND_LITERAL(ob, "<thead>\n");
279
- BLOB_APPEND_BLOB(ob, head_row);
280
- BLOB_APPEND_LITERAL(ob, "</thead>\n<tbody>\n");
276
+ blob_append_literal(ob, "<thead>\n");
277
+ blob_appendb(ob, head_row);
278
+ blob_append_literal(ob, "</thead>\n<tbody>\n");
281279
}
282280
if( rows ){
283
- BLOB_APPEND_BLOB(ob, rows);
281
+ blob_appendb(ob, rows);
284282
}
285283
if( head_row && blob_size(head_row)>0 ){
286
- BLOB_APPEND_LITERAL(ob, "</tbody>\n");
284
+ blob_append_literal(ob, "</tbody>\n");
287285
}
288
- BLOB_APPEND_LITERAL(ob, "</table>\n");
286
+ blob_append_literal(ob, "</table>\n");
289287
}
290288
291289
static void html_table_cell(
292290
struct Blob *ob,
293291
struct Blob *text,
294292
int flags,
295293
void *opaque
296294
){
297295
if( flags & MKD_CELL_HEAD ){
298
- BLOB_APPEND_LITERAL(ob, " <th");
296
+ blob_append_literal(ob, " <th");
299297
}else{
300
- BLOB_APPEND_LITERAL(ob, " <td");
298
+ blob_append_literal(ob, " <td");
301299
}
302300
switch( flags & MKD_CELL_ALIGN_MASK ){
303301
case MKD_CELL_ALIGN_LEFT: {
304
- BLOB_APPEND_LITERAL(ob, " align=\"left\"");
302
+ blob_append_literal(ob, " align=\"left\"");
305303
break;
306304
}
307305
case MKD_CELL_ALIGN_RIGHT: {
308
- BLOB_APPEND_LITERAL(ob, " align=\"right\"");
306
+ blob_append_literal(ob, " align=\"right\"");
309307
break;
310308
}
311309
case MKD_CELL_ALIGN_CENTER: {
312
- BLOB_APPEND_LITERAL(ob, " align=\"center\"");
310
+ blob_append_literal(ob, " align=\"center\"");
313311
break;
314312
}
315313
}
316
- BLOB_APPEND_LITERAL(ob, ">");
317
- BLOB_APPEND_BLOB(ob, text);
314
+ blob_append_literal(ob, ">");
315
+ blob_appendb(ob, text);
318316
if( flags & MKD_CELL_HEAD ){
319
- BLOB_APPEND_LITERAL(ob, "</th>\n");
317
+ blob_append_literal(ob, "</th>\n");
320318
}else{
321
- BLOB_APPEND_LITERAL(ob, "</td>\n");
319
+ blob_append_literal(ob, "</td>\n");
322320
}
323321
}
324322
325323
static void html_table_row(
326324
struct Blob *ob,
327325
struct Blob *cells,
328326
int flags,
329327
void *opaque
330328
){
331
- BLOB_APPEND_LITERAL(ob, " <tr>\n");
332
- BLOB_APPEND_BLOB(ob, cells);
333
- BLOB_APPEND_LITERAL(ob, " </tr>\n");
329
+ blob_append_literal(ob, " <tr>\n");
330
+ blob_appendb(ob, cells);
331
+ blob_append_literal(ob, " </tr>\n");
334332
}
335333
336
-/* Render a token of user provided classes.
334
+/*
335
+** Render a token of user provided classes.
337336
** If bHTML is true then render HTML for (presumably) visible text,
338
-** otherwise just a space-separated list of the derived classes
337
+** otherwise just a space-separated list of the derived classes.
339338
*/
340339
static void append_footnote_upc(
341340
struct Blob *ob,
342341
const struct Blob *upc, /* token of user-provided classes */
343342
int bHTML
344343
){
345344
const char *z = blob_buffer(upc);
346345
int i, n = blob_size(upc);
346
+
347347
if( n<3 ) return;
348348
assert( z[0]=='.' && z[n-1] == ':' );
349
-
350349
if( bHTML ){
351350
blob_append_literal(ob, "<span class='fn-upc'>"
352351
"<span class='fn-upcDot'>.</span>");
353352
}
354353
n = 0;
@@ -394,29 +393,28 @@
394393
char pos[32];
395394
memset(pos,0,32);
396395
assert( locus > 0 );
397396
/* expect BUGs if the following yields compiler warnings */
398397
if( iMark > 0 ){ /* a regular reference to a footnote */
399
-
400
- sprintf(pos, "%s-%i-%s", ctx->unique.c, iMark, l.c);
398
+ sprintf(pos, "%s-%d-%s", ctx->unique.c, iMark, l.c);
401399
if(span && blob_size(span)) {
402400
blob_append_literal(ob,"<span class='");
403401
append_footnote_upc(ob, upc, 0);
404402
blob_append_literal(ob,"notescope' id='noteref");
405403
blob_appendf(ob,"%s'>",pos);
406404
blob_appendb(ob, span);
407405
blob_trim(ob);
408406
blob_append_literal(ob,"<sup class='noteref'><a href='");
409407
BLOB_APPEND_URI(ob, ctx);
410
- blob_appendf(ob,"#footnote%s'>%i</a></sup></span>", pos, iMark);
408
+ blob_appendf(ob,"#footnote%s'>%d</a></sup></span>", pos, iMark);
411409
}else{
412410
blob_trim(ob);
413411
blob_append_literal(ob,"<sup class='");
414412
append_footnote_upc(ob, upc, 0);
415413
blob_append_literal(ob,"noteref'><a href='");
416414
BLOB_APPEND_URI(ob, ctx);
417
- blob_appendf(ob,"#footnote%s' id='noteref%s'>%i</a></sup>",
415
+ blob_appendf(ob,"#footnote%s' id='noteref%s'>%d</a></sup>",
418416
pos, pos, iMark);
419417
}
420418
}else{ /* misreference */
421419
assert( iMark == -1 );
422420
@@ -470,21 +468,19 @@
470468
blob_appendf(ob,"#misref%s-%c'>%c</a>", unique,c, c);
471469
}
472470
if( i < nUsed ) blob_append_literal(ob," &hellip;");
473471
}
474472
blob_append_literal(ob,"</sup>\n<span>Misreference</span>");
475
-
476473
}else if( iMark > 0 ){ /* regular, joined and overnested footnotes */
477474
char pos[24];
478475
int bJoin = 0;
479476
#define _joined_footnote_indicator "<ul class='fn-joined'>"
480477
#define _jfi_sz (sizeof(_joined_footnote_indicator)-1)
481478
assert( text );
482479
assert( blob_size(text) );
483480
memset(pos,0,24);
484
- sprintf(pos, "%s-%i", unique, iMark);
485
-
481
+ sprintf(pos, "%s-%d", unique, iMark);
486482
blob_appendf(ob, "<li id='footnote%s' class='", pos);
487483
if( nUsed ){
488484
if( blob_size(text)>=_jfi_sz &&
489485
!memcmp(blob_buffer(text),_joined_footnote_indicator,_jfi_sz)){
490486
bJoin = 1;
@@ -492,11 +488,10 @@
492488
}
493489
append_footnote_upc(ob, upc, 0);
494490
}else{
495491
blob_append_literal(ob, "fn-toodeep ");
496492
}
497
-
498493
if( nUsed <= 1 ){
499494
blob_append_literal(ob, "fn-monoref'><sup class='fn-backrefs'>");
500495
blob_appendf(ob,"<a id='footnote%s-a' href='", pos);
501496
BLOB_APPEND_URI(ob, ctx);
502497
blob_appendf(ob,"#noteref%s-a'>^</a>", pos);
@@ -554,10 +549,11 @@
554549
html_escape(ob, blob_buffer(text), blob_size(text));
555550
blob_append_literal(ob,"</code></pre>");
556551
}
557552
blob_append_literal(ob, "\n</li>\n");
558553
}
554
+
559555
static void html_footnotes(
560556
struct Blob *ob, const struct Blob *items, void *opaque
561557
){
562558
if( items && blob_size(items) ){
563559
blob_append_literal(ob,
@@ -579,21 +575,21 @@
579575
struct Blob *link,
580576
enum mkd_autolink type,
581577
void *opaque
582578
){
583579
if( !link || blob_size(link)<=0 ) return 0;
584
- BLOB_APPEND_LITERAL(ob, "<a href=\"");
585
- if( type==MKDA_IMPLICIT_EMAIL ) BLOB_APPEND_LITERAL(ob, "mailto:");
580
+ blob_append_literal(ob, "<a href=\"");
581
+ if( type==MKDA_IMPLICIT_EMAIL ) blob_append_literal(ob, "mailto:");
586582
html_quote(ob, blob_buffer(link), blob_size(link));
587
- BLOB_APPEND_LITERAL(ob, "\">");
583
+ blob_append_literal(ob, "\">");
588584
if( type==MKDA_EXPLICIT_EMAIL && blob_size(link)>7 ){
589585
/* remove "mailto:" from displayed text */
590586
html_escape(ob, blob_buffer(link)+7, blob_size(link)-7);
591587
}else{
592588
html_escape(ob, blob_buffer(link), blob_size(link));
593589
}
594
- BLOB_APPEND_LITERAL(ob, "</a>");
590
+ blob_append_literal(ob, "</a>");
595591
return 1;
596592
}
597593
598594
/*
599595
** The nSrc bytes at zSrc[] are Pikchr input text (allegedly). Process that
@@ -682,13 +678,13 @@
682678
){
683679
if( text==0 ){
684680
/* no-op */
685681
}else if( nSep<=2 ){
686682
/* One or two graves: an in-line code span */
687
- BLOB_APPEND_LITERAL(ob, "<code>");
683
+ blob_append_literal(ob, "<code>");
688684
html_escape(ob, blob_buffer(text), blob_size(text));
689
- BLOB_APPEND_LITERAL(ob, "</code>");
685
+ blob_append_literal(ob, "</code>");
690686
}else{
691687
/* Three or more graves: a fenced code block */
692688
int n = blob_size(text);
693689
const char *z = blob_buffer(text);
694690
int i;
@@ -720,25 +716,25 @@
720716
struct Blob *ob,
721717
struct Blob *text,
722718
char c,
723719
void *opaque
724720
){
725
- BLOB_APPEND_LITERAL(ob, "<strong>");
726
- BLOB_APPEND_BLOB(ob, text);
727
- BLOB_APPEND_LITERAL(ob, "</strong>");
721
+ blob_append_literal(ob, "<strong>");
722
+ blob_appendb(ob, text);
723
+ blob_append_literal(ob, "</strong>");
728724
return 1;
729725
}
730726
731727
static int html_emphasis(
732728
struct Blob *ob,
733729
struct Blob *text,
734730
char c,
735731
void *opaque
736732
){
737
- BLOB_APPEND_LITERAL(ob, "<em>");
738
- BLOB_APPEND_BLOB(ob, text);
739
- BLOB_APPEND_LITERAL(ob, "</em>");
733
+ blob_append_literal(ob, "<em>");
734
+ blob_appendb(ob, text);
735
+ blob_append_literal(ob, "</em>");
740736
return 1;
741737
}
742738
743739
static int html_image(
744740
struct Blob *ob,
@@ -745,24 +741,24 @@
745741
struct Blob *link,
746742
struct Blob *title,
747743
struct Blob *alt,
748744
void *opaque
749745
){
750
- BLOB_APPEND_LITERAL(ob, "<img src=\"");
746
+ blob_append_literal(ob, "<img src=\"");
751747
html_quote(ob, blob_buffer(link), blob_size(link));
752
- BLOB_APPEND_LITERAL(ob, "\" alt=\"");
748
+ blob_append_literal(ob, "\" alt=\"");
753749
html_quote(ob, blob_buffer(alt), blob_size(alt));
754750
if( title && blob_size(title)>0 ){
755
- BLOB_APPEND_LITERAL(ob, "\" title=\"");
751
+ blob_append_literal(ob, "\" title=\"");
756752
html_quote(ob, blob_buffer(title), blob_size(title));
757753
}
758
- BLOB_APPEND_LITERAL(ob, "\" />");
754
+ blob_append_literal(ob, "\" />");
759755
return 1;
760756
}
761757
762758
static int html_linebreak(struct Blob *ob, void *opaque){
763
- BLOB_APPEND_LITERAL(ob, "<br />\n");
759
+ blob_append_literal(ob, "<br />\n");
764760
return 1;
765761
}
766762
767763
static int html_link(
768764
struct Blob *ob,
@@ -783,13 +779,13 @@
783779
WIKI_MARKDOWNLINKS
784780
;
785781
wiki_resolve_hyperlink(ob, flags, zLink, zClose, sizeof(zClose), 0, zTitle);
786782
}
787783
if( blob_size(content)==0 ){
788
- if( link ) BLOB_APPEND_BLOB(ob, link);
784
+ if( link ) blob_appendb(ob, link);
789785
}else{
790
- BLOB_APPEND_BLOB(ob, content);
786
+ blob_appendb(ob, content);
791787
}
792788
blob_append(ob, zClose, -1);
793789
return 1;
794790
}
795791
@@ -797,13 +793,13 @@
797793
struct Blob *ob,
798794
struct Blob *text,
799795
char c,
800796
void *opaque
801797
){
802
- BLOB_APPEND_LITERAL(ob, "<strong><em>");
803
- BLOB_APPEND_BLOB(ob, text);
804
- BLOB_APPEND_LITERAL(ob, "</em></strong>");
798
+ blob_append_literal(ob, "<strong><em>");
799
+ blob_appendb(ob, text);
800
+ blob_append_literal(ob, "</em></strong>");
805801
return 1;
806802
}
807803
808804
809805
static void html_normal_text(struct Blob *ob, struct Blob *text, void *opaque){
810806
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -29,11 +29,19 @@
29 struct Blob *output_title,
30 struct Blob *output_body);
31
32 #endif /* INTERFACE */
33
34 typedef union { uint64_t u; char c[8]; unsigned char b[8]; } bitfield64_t;
 
 
 
 
 
 
 
 
35
36 /*
37 ** An instance of the following structure is passed through the
38 ** "opaque" pointer.
39 */
@@ -50,20 +58,10 @@
50
51 /* INTER_BLOCK -- skip a line between block level elements */
52 #define INTER_BLOCK(ob) \
53 do { if( blob_size(ob)>0 ) blob_append_char(ob, '\n'); } while (0)
54
55 /* BLOB_APPEND_LITERAL -- append a string literal to a blob
56 ** TODO: Refactor all invocations to use global macro blob_append_literal()
57 */
58 #define BLOB_APPEND_LITERAL blob_append_literal
59
60 /* BLOB_APPEND_BLOB -- append blob contents to another
61 ** TODO: Refactor all invocations to use global macro blob_appendb()
62 */
63 #define BLOB_APPEND_BLOB(dest, src) blob_appendb((dest), (src))
64
65 #ifndef FOOTNOTES_WITHOUT_URI
66 #define BLOB_APPEND_URI(dest,ctx) blob_appendb(dest,&((ctx)->reqURI))
67 #else
68 #define BLOB_APPEND_URI(dest,ctx)
69 #endif
@@ -106,19 +104,19 @@
106 i++;
107 }
108 blob_append(ob, data+beg, i-beg);
109 while( i<size ){
110 if( data[i]=='<' ){
111 BLOB_APPEND_LITERAL(ob, "&lt;");
112 }else if( data[i]=='>' ){
113 BLOB_APPEND_LITERAL(ob, "&gt;");
114 }else if( data[i]=='&' ){
115 BLOB_APPEND_LITERAL(ob, "&amp;");
116 }else if( data[i]=='"' ){
117 BLOB_APPEND_LITERAL(ob, "&quot;");
118 }else if( data[i]=='\'' ){
119 BLOB_APPEND_LITERAL(ob, "&#39;");
120 }else{
121 break;
122 }
123 i++;
124 }
@@ -136,15 +134,15 @@
136 i++;
137 }
138 blob_append(ob, data+beg, i-beg);
139 while( i<size ){
140 if( data[i]=='<' ){
141 BLOB_APPEND_LITERAL(ob, "&lt;");
142 }else if( data[i]=='>' ){
143 BLOB_APPEND_LITERAL(ob, "&gt;");
144 }else if( data[i]=='&' ){
145 BLOB_APPEND_LITERAL(ob, "&amp;");
146 }else{
147 break;
148 }
149 i++;
150 }
@@ -157,17 +155,17 @@
157 /* Size of the prolog: "<div class='markdown'>\n" */
158 #define PROLOG_SIZE 23
159
160 static void html_prolog(struct Blob *ob, void *opaque){
161 INTER_BLOCK(ob);
162 BLOB_APPEND_LITERAL(ob, "<div class=\"markdown\">\n");
163 assert( blob_size(ob)==PROLOG_SIZE );
164 }
165
166 static void html_epilog(struct Blob *ob, void *opaque){
167 INTER_BLOCK(ob);
168 BLOB_APPEND_LITERAL(ob, "</div>\n");
169 }
170
171 static void html_blockhtml(struct Blob *ob, struct Blob *text, void *opaque){
172 char *data = blob_buffer(text);
173 size_t size = blob_size(text);
@@ -185,25 +183,25 @@
185 blob_append(title, data+nTag, size - nTag - 5);
186 return;
187 }
188 INTER_BLOCK(ob);
189 blob_append(ob, data, size);
190 BLOB_APPEND_LITERAL(ob, "\n");
191 }
192
193 static void html_blockcode(struct Blob *ob, struct Blob *text, void *opaque){
194 INTER_BLOCK(ob);
195 BLOB_APPEND_LITERAL(ob, "<pre><code>");
196 html_escape(ob, blob_buffer(text), blob_size(text));
197 BLOB_APPEND_LITERAL(ob, "</code></pre>\n");
198 }
199
200 static void html_blockquote(struct Blob *ob, struct Blob *text, void *opaque){
201 INTER_BLOCK(ob);
202 BLOB_APPEND_LITERAL(ob, "<blockquote>\n");
203 BLOB_APPEND_BLOB(ob, text);
204 BLOB_APPEND_LITERAL(ob, "</blockquote>\n");
205 }
206
207 static void html_header(
208 struct Blob *ob,
209 struct Blob *text,
@@ -212,22 +210,22 @@
212 ){
213 struct Blob *title = ((MarkdownToHtml*)opaque)->output_title;
214 /* The first header at the beginning of a text is considered as
215 * a title and not output. */
216 if( blob_size(ob)<=PROLOG_SIZE && title!=0 && blob_size(title)==0 ){
217 BLOB_APPEND_BLOB(title, text);
218 return;
219 }
220 INTER_BLOCK(ob);
221 blob_appendf(ob, "<h%d>", level);
222 BLOB_APPEND_BLOB(ob, text);
223 blob_appendf(ob, "</h%d>", level);
224 }
225
226 static void html_hrule(struct Blob *ob, void *opaque){
227 INTER_BLOCK(ob);
228 BLOB_APPEND_LITERAL(ob, "<hr />\n");
229 }
230
231
232 static void html_list(
233 struct Blob *ob,
@@ -238,11 +236,11 @@
238 char ol[] = "ol";
239 char ul[] = "ul";
240 char *tag = (flags & MKD_LIST_ORDERED) ? ol : ul;
241 INTER_BLOCK(ob);
242 blob_appendf(ob, "<%s>\n", tag);
243 BLOB_APPEND_BLOB(ob, text);
244 blob_appendf(ob, "</%s>\n", tag);
245 }
246
247 static void html_list_item(
248 struct Blob *ob,
@@ -251,20 +249,20 @@
251 void *opaque
252 ){
253 char *text_data = blob_buffer(text);
254 size_t text_size = blob_size(text);
255 while( text_size>0 && text_data[text_size-1]=='\n' ) text_size--;
256 BLOB_APPEND_LITERAL(ob, "<li>");
257 blob_append(ob, text_data, text_size);
258 BLOB_APPEND_LITERAL(ob, "</li>\n");
259 }
260
261 static void html_paragraph(struct Blob *ob, struct Blob *text, void *opaque){
262 INTER_BLOCK(ob);
263 BLOB_APPEND_LITERAL(ob, "<p>");
264 BLOB_APPEND_BLOB(ob, text);
265 BLOB_APPEND_LITERAL(ob, "</p>\n");
266 }
267
268
269 static void html_table(
270 struct Blob *ob,
@@ -271,84 +269,85 @@
271 struct Blob *head_row,
272 struct Blob *rows,
273 void *opaque
274 ){
275 INTER_BLOCK(ob);
276 BLOB_APPEND_LITERAL(ob, "<table>\n");
277 if( head_row && blob_size(head_row)>0 ){
278 BLOB_APPEND_LITERAL(ob, "<thead>\n");
279 BLOB_APPEND_BLOB(ob, head_row);
280 BLOB_APPEND_LITERAL(ob, "</thead>\n<tbody>\n");
281 }
282 if( rows ){
283 BLOB_APPEND_BLOB(ob, rows);
284 }
285 if( head_row && blob_size(head_row)>0 ){
286 BLOB_APPEND_LITERAL(ob, "</tbody>\n");
287 }
288 BLOB_APPEND_LITERAL(ob, "</table>\n");
289 }
290
291 static void html_table_cell(
292 struct Blob *ob,
293 struct Blob *text,
294 int flags,
295 void *opaque
296 ){
297 if( flags & MKD_CELL_HEAD ){
298 BLOB_APPEND_LITERAL(ob, " <th");
299 }else{
300 BLOB_APPEND_LITERAL(ob, " <td");
301 }
302 switch( flags & MKD_CELL_ALIGN_MASK ){
303 case MKD_CELL_ALIGN_LEFT: {
304 BLOB_APPEND_LITERAL(ob, " align=\"left\"");
305 break;
306 }
307 case MKD_CELL_ALIGN_RIGHT: {
308 BLOB_APPEND_LITERAL(ob, " align=\"right\"");
309 break;
310 }
311 case MKD_CELL_ALIGN_CENTER: {
312 BLOB_APPEND_LITERAL(ob, " align=\"center\"");
313 break;
314 }
315 }
316 BLOB_APPEND_LITERAL(ob, ">");
317 BLOB_APPEND_BLOB(ob, text);
318 if( flags & MKD_CELL_HEAD ){
319 BLOB_APPEND_LITERAL(ob, "</th>\n");
320 }else{
321 BLOB_APPEND_LITERAL(ob, "</td>\n");
322 }
323 }
324
325 static void html_table_row(
326 struct Blob *ob,
327 struct Blob *cells,
328 int flags,
329 void *opaque
330 ){
331 BLOB_APPEND_LITERAL(ob, " <tr>\n");
332 BLOB_APPEND_BLOB(ob, cells);
333 BLOB_APPEND_LITERAL(ob, " </tr>\n");
334 }
335
336 /* Render a token of user provided classes.
 
337 ** If bHTML is true then render HTML for (presumably) visible text,
338 ** otherwise just a space-separated list of the derived classes
339 */
340 static void append_footnote_upc(
341 struct Blob *ob,
342 const struct Blob *upc, /* token of user-provided classes */
343 int bHTML
344 ){
345 const char *z = blob_buffer(upc);
346 int i, n = blob_size(upc);
 
347 if( n<3 ) return;
348 assert( z[0]=='.' && z[n-1] == ':' );
349
350 if( bHTML ){
351 blob_append_literal(ob, "<span class='fn-upc'>"
352 "<span class='fn-upcDot'>.</span>");
353 }
354 n = 0;
@@ -394,29 +393,28 @@
394 char pos[32];
395 memset(pos,0,32);
396 assert( locus > 0 );
397 /* expect BUGs if the following yields compiler warnings */
398 if( iMark > 0 ){ /* a regular reference to a footnote */
399
400 sprintf(pos, "%s-%i-%s", ctx->unique.c, iMark, l.c);
401 if(span && blob_size(span)) {
402 blob_append_literal(ob,"<span class='");
403 append_footnote_upc(ob, upc, 0);
404 blob_append_literal(ob,"notescope' id='noteref");
405 blob_appendf(ob,"%s'>",pos);
406 blob_appendb(ob, span);
407 blob_trim(ob);
408 blob_append_literal(ob,"<sup class='noteref'><a href='");
409 BLOB_APPEND_URI(ob, ctx);
410 blob_appendf(ob,"#footnote%s'>%i</a></sup></span>", pos, iMark);
411 }else{
412 blob_trim(ob);
413 blob_append_literal(ob,"<sup class='");
414 append_footnote_upc(ob, upc, 0);
415 blob_append_literal(ob,"noteref'><a href='");
416 BLOB_APPEND_URI(ob, ctx);
417 blob_appendf(ob,"#footnote%s' id='noteref%s'>%i</a></sup>",
418 pos, pos, iMark);
419 }
420 }else{ /* misreference */
421 assert( iMark == -1 );
422
@@ -470,21 +468,19 @@
470 blob_appendf(ob,"#misref%s-%c'>%c</a>", unique,c, c);
471 }
472 if( i < nUsed ) blob_append_literal(ob," &hellip;");
473 }
474 blob_append_literal(ob,"</sup>\n<span>Misreference</span>");
475
476 }else if( iMark > 0 ){ /* regular, joined and overnested footnotes */
477 char pos[24];
478 int bJoin = 0;
479 #define _joined_footnote_indicator "<ul class='fn-joined'>"
480 #define _jfi_sz (sizeof(_joined_footnote_indicator)-1)
481 assert( text );
482 assert( blob_size(text) );
483 memset(pos,0,24);
484 sprintf(pos, "%s-%i", unique, iMark);
485
486 blob_appendf(ob, "<li id='footnote%s' class='", pos);
487 if( nUsed ){
488 if( blob_size(text)>=_jfi_sz &&
489 !memcmp(blob_buffer(text),_joined_footnote_indicator,_jfi_sz)){
490 bJoin = 1;
@@ -492,11 +488,10 @@
492 }
493 append_footnote_upc(ob, upc, 0);
494 }else{
495 blob_append_literal(ob, "fn-toodeep ");
496 }
497
498 if( nUsed <= 1 ){
499 blob_append_literal(ob, "fn-monoref'><sup class='fn-backrefs'>");
500 blob_appendf(ob,"<a id='footnote%s-a' href='", pos);
501 BLOB_APPEND_URI(ob, ctx);
502 blob_appendf(ob,"#noteref%s-a'>^</a>", pos);
@@ -554,10 +549,11 @@
554 html_escape(ob, blob_buffer(text), blob_size(text));
555 blob_append_literal(ob,"</code></pre>");
556 }
557 blob_append_literal(ob, "\n</li>\n");
558 }
 
559 static void html_footnotes(
560 struct Blob *ob, const struct Blob *items, void *opaque
561 ){
562 if( items && blob_size(items) ){
563 blob_append_literal(ob,
@@ -579,21 +575,21 @@
579 struct Blob *link,
580 enum mkd_autolink type,
581 void *opaque
582 ){
583 if( !link || blob_size(link)<=0 ) return 0;
584 BLOB_APPEND_LITERAL(ob, "<a href=\"");
585 if( type==MKDA_IMPLICIT_EMAIL ) BLOB_APPEND_LITERAL(ob, "mailto:");
586 html_quote(ob, blob_buffer(link), blob_size(link));
587 BLOB_APPEND_LITERAL(ob, "\">");
588 if( type==MKDA_EXPLICIT_EMAIL && blob_size(link)>7 ){
589 /* remove "mailto:" from displayed text */
590 html_escape(ob, blob_buffer(link)+7, blob_size(link)-7);
591 }else{
592 html_escape(ob, blob_buffer(link), blob_size(link));
593 }
594 BLOB_APPEND_LITERAL(ob, "</a>");
595 return 1;
596 }
597
598 /*
599 ** The nSrc bytes at zSrc[] are Pikchr input text (allegedly). Process that
@@ -682,13 +678,13 @@
682 ){
683 if( text==0 ){
684 /* no-op */
685 }else if( nSep<=2 ){
686 /* One or two graves: an in-line code span */
687 BLOB_APPEND_LITERAL(ob, "<code>");
688 html_escape(ob, blob_buffer(text), blob_size(text));
689 BLOB_APPEND_LITERAL(ob, "</code>");
690 }else{
691 /* Three or more graves: a fenced code block */
692 int n = blob_size(text);
693 const char *z = blob_buffer(text);
694 int i;
@@ -720,25 +716,25 @@
720 struct Blob *ob,
721 struct Blob *text,
722 char c,
723 void *opaque
724 ){
725 BLOB_APPEND_LITERAL(ob, "<strong>");
726 BLOB_APPEND_BLOB(ob, text);
727 BLOB_APPEND_LITERAL(ob, "</strong>");
728 return 1;
729 }
730
731 static int html_emphasis(
732 struct Blob *ob,
733 struct Blob *text,
734 char c,
735 void *opaque
736 ){
737 BLOB_APPEND_LITERAL(ob, "<em>");
738 BLOB_APPEND_BLOB(ob, text);
739 BLOB_APPEND_LITERAL(ob, "</em>");
740 return 1;
741 }
742
743 static int html_image(
744 struct Blob *ob,
@@ -745,24 +741,24 @@
745 struct Blob *link,
746 struct Blob *title,
747 struct Blob *alt,
748 void *opaque
749 ){
750 BLOB_APPEND_LITERAL(ob, "<img src=\"");
751 html_quote(ob, blob_buffer(link), blob_size(link));
752 BLOB_APPEND_LITERAL(ob, "\" alt=\"");
753 html_quote(ob, blob_buffer(alt), blob_size(alt));
754 if( title && blob_size(title)>0 ){
755 BLOB_APPEND_LITERAL(ob, "\" title=\"");
756 html_quote(ob, blob_buffer(title), blob_size(title));
757 }
758 BLOB_APPEND_LITERAL(ob, "\" />");
759 return 1;
760 }
761
762 static int html_linebreak(struct Blob *ob, void *opaque){
763 BLOB_APPEND_LITERAL(ob, "<br />\n");
764 return 1;
765 }
766
767 static int html_link(
768 struct Blob *ob,
@@ -783,13 +779,13 @@
783 WIKI_MARKDOWNLINKS
784 ;
785 wiki_resolve_hyperlink(ob, flags, zLink, zClose, sizeof(zClose), 0, zTitle);
786 }
787 if( blob_size(content)==0 ){
788 if( link ) BLOB_APPEND_BLOB(ob, link);
789 }else{
790 BLOB_APPEND_BLOB(ob, content);
791 }
792 blob_append(ob, zClose, -1);
793 return 1;
794 }
795
@@ -797,13 +793,13 @@
797 struct Blob *ob,
798 struct Blob *text,
799 char c,
800 void *opaque
801 ){
802 BLOB_APPEND_LITERAL(ob, "<strong><em>");
803 BLOB_APPEND_BLOB(ob, text);
804 BLOB_APPEND_LITERAL(ob, "</em></strong>");
805 return 1;
806 }
807
808
809 static void html_normal_text(struct Blob *ob, struct Blob *text, void *opaque){
810
--- src/markdown_html.c
+++ src/markdown_html.c
@@ -29,11 +29,19 @@
29 struct Blob *output_title,
30 struct Blob *output_body);
31
32 #endif /* INTERFACE */
33
34 /*
35 ** Markdown-internal helper for generating unique link reference IDs.
36 */
37 typedef union bitfield64_t bitfield64_t;
38 union bitfield64_t{
39 uint64_t u;
40 char c[8];
41 unsigned char b[8];
42 };
43
44 /*
45 ** An instance of the following structure is passed through the
46 ** "opaque" pointer.
47 */
@@ -50,20 +58,10 @@
58
59 /* INTER_BLOCK -- skip a line between block level elements */
60 #define INTER_BLOCK(ob) \
61 do { if( blob_size(ob)>0 ) blob_append_char(ob, '\n'); } while (0)
62
 
 
 
 
 
 
 
 
 
 
63 #ifndef FOOTNOTES_WITHOUT_URI
64 #define BLOB_APPEND_URI(dest,ctx) blob_appendb(dest,&((ctx)->reqURI))
65 #else
66 #define BLOB_APPEND_URI(dest,ctx)
67 #endif
@@ -106,19 +104,19 @@
104 i++;
105 }
106 blob_append(ob, data+beg, i-beg);
107 while( i<size ){
108 if( data[i]=='<' ){
109 blob_append_literal(ob, "&lt;");
110 }else if( data[i]=='>' ){
111 blob_append_literal(ob, "&gt;");
112 }else if( data[i]=='&' ){
113 blob_append_literal(ob, "&amp;");
114 }else if( data[i]=='"' ){
115 blob_append_literal(ob, "&quot;");
116 }else if( data[i]=='\'' ){
117 blob_append_literal(ob, "&#39;");
118 }else{
119 break;
120 }
121 i++;
122 }
@@ -136,15 +134,15 @@
134 i++;
135 }
136 blob_append(ob, data+beg, i-beg);
137 while( i<size ){
138 if( data[i]=='<' ){
139 blob_append_literal(ob, "&lt;");
140 }else if( data[i]=='>' ){
141 blob_append_literal(ob, "&gt;");
142 }else if( data[i]=='&' ){
143 blob_append_literal(ob, "&amp;");
144 }else{
145 break;
146 }
147 i++;
148 }
@@ -157,17 +155,17 @@
155 /* Size of the prolog: "<div class='markdown'>\n" */
156 #define PROLOG_SIZE 23
157
158 static void html_prolog(struct Blob *ob, void *opaque){
159 INTER_BLOCK(ob);
160 blob_append_literal(ob, "<div class=\"markdown\">\n");
161 assert( blob_size(ob)==PROLOG_SIZE );
162 }
163
164 static void html_epilog(struct Blob *ob, void *opaque){
165 INTER_BLOCK(ob);
166 blob_append_literal(ob, "</div>\n");
167 }
168
169 static void html_blockhtml(struct Blob *ob, struct Blob *text, void *opaque){
170 char *data = blob_buffer(text);
171 size_t size = blob_size(text);
@@ -185,25 +183,25 @@
183 blob_append(title, data+nTag, size - nTag - 5);
184 return;
185 }
186 INTER_BLOCK(ob);
187 blob_append(ob, data, size);
188 blob_append_literal(ob, "\n");
189 }
190
191 static void html_blockcode(struct Blob *ob, struct Blob *text, void *opaque){
192 INTER_BLOCK(ob);
193 blob_append_literal(ob, "<pre><code>");
194 html_escape(ob, blob_buffer(text), blob_size(text));
195 blob_append_literal(ob, "</code></pre>\n");
196 }
197
198 static void html_blockquote(struct Blob *ob, struct Blob *text, void *opaque){
199 INTER_BLOCK(ob);
200 blob_append_literal(ob, "<blockquote>\n");
201 blob_appendb(ob, text);
202 blob_append_literal(ob, "</blockquote>\n");
203 }
204
205 static void html_header(
206 struct Blob *ob,
207 struct Blob *text,
@@ -212,22 +210,22 @@
210 ){
211 struct Blob *title = ((MarkdownToHtml*)opaque)->output_title;
212 /* The first header at the beginning of a text is considered as
213 * a title and not output. */
214 if( blob_size(ob)<=PROLOG_SIZE && title!=0 && blob_size(title)==0 ){
215 blob_appendb(title, text);
216 return;
217 }
218 INTER_BLOCK(ob);
219 blob_appendf(ob, "<h%d>", level);
220 blob_appendb(ob, text);
221 blob_appendf(ob, "</h%d>", level);
222 }
223
224 static void html_hrule(struct Blob *ob, void *opaque){
225 INTER_BLOCK(ob);
226 blob_append_literal(ob, "<hr />\n");
227 }
228
229
230 static void html_list(
231 struct Blob *ob,
@@ -238,11 +236,11 @@
236 char ol[] = "ol";
237 char ul[] = "ul";
238 char *tag = (flags & MKD_LIST_ORDERED) ? ol : ul;
239 INTER_BLOCK(ob);
240 blob_appendf(ob, "<%s>\n", tag);
241 blob_appendb(ob, text);
242 blob_appendf(ob, "</%s>\n", tag);
243 }
244
245 static void html_list_item(
246 struct Blob *ob,
@@ -251,20 +249,20 @@
249 void *opaque
250 ){
251 char *text_data = blob_buffer(text);
252 size_t text_size = blob_size(text);
253 while( text_size>0 && text_data[text_size-1]=='\n' ) text_size--;
254 blob_append_literal(ob, "<li>");
255 blob_append(ob, text_data, text_size);
256 blob_append_literal(ob, "</li>\n");
257 }
258
259 static void html_paragraph(struct Blob *ob, struct Blob *text, void *opaque){
260 INTER_BLOCK(ob);
261 blob_append_literal(ob, "<p>");
262 blob_appendb(ob, text);
263 blob_append_literal(ob, "</p>\n");
264 }
265
266
267 static void html_table(
268 struct Blob *ob,
@@ -271,84 +269,85 @@
269 struct Blob *head_row,
270 struct Blob *rows,
271 void *opaque
272 ){
273 INTER_BLOCK(ob);
274 blob_append_literal(ob, "<table>\n");
275 if( head_row && blob_size(head_row)>0 ){
276 blob_append_literal(ob, "<thead>\n");
277 blob_appendb(ob, head_row);
278 blob_append_literal(ob, "</thead>\n<tbody>\n");
279 }
280 if( rows ){
281 blob_appendb(ob, rows);
282 }
283 if( head_row && blob_size(head_row)>0 ){
284 blob_append_literal(ob, "</tbody>\n");
285 }
286 blob_append_literal(ob, "</table>\n");
287 }
288
289 static void html_table_cell(
290 struct Blob *ob,
291 struct Blob *text,
292 int flags,
293 void *opaque
294 ){
295 if( flags & MKD_CELL_HEAD ){
296 blob_append_literal(ob, " <th");
297 }else{
298 blob_append_literal(ob, " <td");
299 }
300 switch( flags & MKD_CELL_ALIGN_MASK ){
301 case MKD_CELL_ALIGN_LEFT: {
302 blob_append_literal(ob, " align=\"left\"");
303 break;
304 }
305 case MKD_CELL_ALIGN_RIGHT: {
306 blob_append_literal(ob, " align=\"right\"");
307 break;
308 }
309 case MKD_CELL_ALIGN_CENTER: {
310 blob_append_literal(ob, " align=\"center\"");
311 break;
312 }
313 }
314 blob_append_literal(ob, ">");
315 blob_appendb(ob, text);
316 if( flags & MKD_CELL_HEAD ){
317 blob_append_literal(ob, "</th>\n");
318 }else{
319 blob_append_literal(ob, "</td>\n");
320 }
321 }
322
323 static void html_table_row(
324 struct Blob *ob,
325 struct Blob *cells,
326 int flags,
327 void *opaque
328 ){
329 blob_append_literal(ob, " <tr>\n");
330 blob_appendb(ob, cells);
331 blob_append_literal(ob, " </tr>\n");
332 }
333
334 /*
335 ** Render a token of user provided classes.
336 ** If bHTML is true then render HTML for (presumably) visible text,
337 ** otherwise just a space-separated list of the derived classes.
338 */
339 static void append_footnote_upc(
340 struct Blob *ob,
341 const struct Blob *upc, /* token of user-provided classes */
342 int bHTML
343 ){
344 const char *z = blob_buffer(upc);
345 int i, n = blob_size(upc);
346
347 if( n<3 ) return;
348 assert( z[0]=='.' && z[n-1] == ':' );
 
349 if( bHTML ){
350 blob_append_literal(ob, "<span class='fn-upc'>"
351 "<span class='fn-upcDot'>.</span>");
352 }
353 n = 0;
@@ -394,29 +393,28 @@
393 char pos[32];
394 memset(pos,0,32);
395 assert( locus > 0 );
396 /* expect BUGs if the following yields compiler warnings */
397 if( iMark > 0 ){ /* a regular reference to a footnote */
398 sprintf(pos, "%s-%d-%s", ctx->unique.c, iMark, l.c);
 
399 if(span && blob_size(span)) {
400 blob_append_literal(ob,"<span class='");
401 append_footnote_upc(ob, upc, 0);
402 blob_append_literal(ob,"notescope' id='noteref");
403 blob_appendf(ob,"%s'>",pos);
404 blob_appendb(ob, span);
405 blob_trim(ob);
406 blob_append_literal(ob,"<sup class='noteref'><a href='");
407 BLOB_APPEND_URI(ob, ctx);
408 blob_appendf(ob,"#footnote%s'>%d</a></sup></span>", pos, iMark);
409 }else{
410 blob_trim(ob);
411 blob_append_literal(ob,"<sup class='");
412 append_footnote_upc(ob, upc, 0);
413 blob_append_literal(ob,"noteref'><a href='");
414 BLOB_APPEND_URI(ob, ctx);
415 blob_appendf(ob,"#footnote%s' id='noteref%s'>%d</a></sup>",
416 pos, pos, iMark);
417 }
418 }else{ /* misreference */
419 assert( iMark == -1 );
420
@@ -470,21 +468,19 @@
468 blob_appendf(ob,"#misref%s-%c'>%c</a>", unique,c, c);
469 }
470 if( i < nUsed ) blob_append_literal(ob," &hellip;");
471 }
472 blob_append_literal(ob,"</sup>\n<span>Misreference</span>");
 
473 }else if( iMark > 0 ){ /* regular, joined and overnested footnotes */
474 char pos[24];
475 int bJoin = 0;
476 #define _joined_footnote_indicator "<ul class='fn-joined'>"
477 #define _jfi_sz (sizeof(_joined_footnote_indicator)-1)
478 assert( text );
479 assert( blob_size(text) );
480 memset(pos,0,24);
481 sprintf(pos, "%s-%d", unique, iMark);
 
482 blob_appendf(ob, "<li id='footnote%s' class='", pos);
483 if( nUsed ){
484 if( blob_size(text)>=_jfi_sz &&
485 !memcmp(blob_buffer(text),_joined_footnote_indicator,_jfi_sz)){
486 bJoin = 1;
@@ -492,11 +488,10 @@
488 }
489 append_footnote_upc(ob, upc, 0);
490 }else{
491 blob_append_literal(ob, "fn-toodeep ");
492 }
 
493 if( nUsed <= 1 ){
494 blob_append_literal(ob, "fn-monoref'><sup class='fn-backrefs'>");
495 blob_appendf(ob,"<a id='footnote%s-a' href='", pos);
496 BLOB_APPEND_URI(ob, ctx);
497 blob_appendf(ob,"#noteref%s-a'>^</a>", pos);
@@ -554,10 +549,11 @@
549 html_escape(ob, blob_buffer(text), blob_size(text));
550 blob_append_literal(ob,"</code></pre>");
551 }
552 blob_append_literal(ob, "\n</li>\n");
553 }
554
555 static void html_footnotes(
556 struct Blob *ob, const struct Blob *items, void *opaque
557 ){
558 if( items && blob_size(items) ){
559 blob_append_literal(ob,
@@ -579,21 +575,21 @@
575 struct Blob *link,
576 enum mkd_autolink type,
577 void *opaque
578 ){
579 if( !link || blob_size(link)<=0 ) return 0;
580 blob_append_literal(ob, "<a href=\"");
581 if( type==MKDA_IMPLICIT_EMAIL ) blob_append_literal(ob, "mailto:");
582 html_quote(ob, blob_buffer(link), blob_size(link));
583 blob_append_literal(ob, "\">");
584 if( type==MKDA_EXPLICIT_EMAIL && blob_size(link)>7 ){
585 /* remove "mailto:" from displayed text */
586 html_escape(ob, blob_buffer(link)+7, blob_size(link)-7);
587 }else{
588 html_escape(ob, blob_buffer(link), blob_size(link));
589 }
590 blob_append_literal(ob, "</a>");
591 return 1;
592 }
593
594 /*
595 ** The nSrc bytes at zSrc[] are Pikchr input text (allegedly). Process that
@@ -682,13 +678,13 @@
678 ){
679 if( text==0 ){
680 /* no-op */
681 }else if( nSep<=2 ){
682 /* One or two graves: an in-line code span */
683 blob_append_literal(ob, "<code>");
684 html_escape(ob, blob_buffer(text), blob_size(text));
685 blob_append_literal(ob, "</code>");
686 }else{
687 /* Three or more graves: a fenced code block */
688 int n = blob_size(text);
689 const char *z = blob_buffer(text);
690 int i;
@@ -720,25 +716,25 @@
716 struct Blob *ob,
717 struct Blob *text,
718 char c,
719 void *opaque
720 ){
721 blob_append_literal(ob, "<strong>");
722 blob_appendb(ob, text);
723 blob_append_literal(ob, "</strong>");
724 return 1;
725 }
726
727 static int html_emphasis(
728 struct Blob *ob,
729 struct Blob *text,
730 char c,
731 void *opaque
732 ){
733 blob_append_literal(ob, "<em>");
734 blob_appendb(ob, text);
735 blob_append_literal(ob, "</em>");
736 return 1;
737 }
738
739 static int html_image(
740 struct Blob *ob,
@@ -745,24 +741,24 @@
741 struct Blob *link,
742 struct Blob *title,
743 struct Blob *alt,
744 void *opaque
745 ){
746 blob_append_literal(ob, "<img src=\"");
747 html_quote(ob, blob_buffer(link), blob_size(link));
748 blob_append_literal(ob, "\" alt=\"");
749 html_quote(ob, blob_buffer(alt), blob_size(alt));
750 if( title && blob_size(title)>0 ){
751 blob_append_literal(ob, "\" title=\"");
752 html_quote(ob, blob_buffer(title), blob_size(title));
753 }
754 blob_append_literal(ob, "\" />");
755 return 1;
756 }
757
758 static int html_linebreak(struct Blob *ob, void *opaque){
759 blob_append_literal(ob, "<br />\n");
760 return 1;
761 }
762
763 static int html_link(
764 struct Blob *ob,
@@ -783,13 +779,13 @@
779 WIKI_MARKDOWNLINKS
780 ;
781 wiki_resolve_hyperlink(ob, flags, zLink, zClose, sizeof(zClose), 0, zTitle);
782 }
783 if( blob_size(content)==0 ){
784 if( link ) blob_appendb(ob, link);
785 }else{
786 blob_appendb(ob, content);
787 }
788 blob_append(ob, zClose, -1);
789 return 1;
790 }
791
@@ -797,13 +793,13 @@
793 struct Blob *ob,
794 struct Blob *text,
795 char c,
796 void *opaque
797 ){
798 blob_append_literal(ob, "<strong><em>");
799 blob_appendb(ob, text);
800 blob_append_literal(ob, "</em></strong>");
801 return 1;
802 }
803
804
805 static void html_normal_text(struct Blob *ob, struct Blob *text, void *opaque){
806
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -1920,14 +1920,14 @@
19201920
blob_reset(&out);
19211921
}
19221922
if( bFnLint && (g.ftntsIssues[0] || g.ftntsIssues[1]
19231923
|| g.ftntsIssues[2] || g.ftntsIssues[3] )){
19241924
fossil_fatal("There were issues with footnotes:\n"
1925
- " %8i misreference%s\n"
1926
- " %8i unreferenced\n"
1927
- " %8i splitted\n"
1928
- " %8i overnested",
1925
+ " %8d misreference%s\n"
1926
+ " %8d unreferenced\n"
1927
+ " %8d splitted\n"
1928
+ " %8d overnested",
19291929
g.ftntsIssues[0], g.ftntsIssues[0]==1?"":"s",
19301930
g.ftntsIssues[1], g.ftntsIssues[2], g.ftntsIssues[3]);
19311931
}
19321932
}
19331933
19341934
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -1920,14 +1920,14 @@
1920 blob_reset(&out);
1921 }
1922 if( bFnLint && (g.ftntsIssues[0] || g.ftntsIssues[1]
1923 || g.ftntsIssues[2] || g.ftntsIssues[3] )){
1924 fossil_fatal("There were issues with footnotes:\n"
1925 " %8i misreference%s\n"
1926 " %8i unreferenced\n"
1927 " %8i splitted\n"
1928 " %8i overnested",
1929 g.ftntsIssues[0], g.ftntsIssues[0]==1?"":"s",
1930 g.ftntsIssues[1], g.ftntsIssues[2], g.ftntsIssues[3]);
1931 }
1932 }
1933
1934
--- src/wikiformat.c
+++ src/wikiformat.c
@@ -1920,14 +1920,14 @@
1920 blob_reset(&out);
1921 }
1922 if( bFnLint && (g.ftntsIssues[0] || g.ftntsIssues[1]
1923 || g.ftntsIssues[2] || g.ftntsIssues[3] )){
1924 fossil_fatal("There were issues with footnotes:\n"
1925 " %8d misreference%s\n"
1926 " %8d unreferenced\n"
1927 " %8d splitted\n"
1928 " %8d overnested",
1929 g.ftntsIssues[0], g.ftntsIssues[0]==1?"":"s",
1930 g.ftntsIssues[1], g.ftntsIssues[2], g.ftntsIssues[3]);
1931 }
1932 }
1933
1934

Keyboard Shortcuts

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