Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Join duplicated footnotes slightly faster. Fix a comment about auxiliary cmp_footnote_id() function. |
---|---|
Downloads: | Tarball | ZIP archive | SQL archive |
Timelines: | family | ancestors | descendants | both | markdown-footnotes |
Files: | files | file ages | folders |
SHA3-256: |
7f6a641808be00f8e68b5c23ce1ec8f3 |
User & Date: | george 2022-02-09 20:09:51 |
Context
2022-02-09
| ||
22:59 | Handle unreferenced footnotes. If a labeled footnote is defined but there are no references to it, then add a special item at the end of footnotes. This item includes a label and the text of the strayed footnote - both rendered verbatim via html_escape(). Default skin makes such items visible and easily distinguishable. The order of such items match the order in the underlying source code. ... (check-in: ada55cd4 user: george tags: markdown-footnotes) | |
20:09 | Join duplicated footnotes slightly faster. Fix a comment about auxiliary cmp_footnote_id() function. ... (check-in: 7f6a6418 user: george tags: markdown-footnotes) | |
19:38 | Fix a misuse of an unsigned integer in the blobReallocMalloc() which can lead to redundant memory reallocations. ... (check-in: 92221aaa user: george tags: markdown-footnotes) | |
Changes
Changes to src/markdown.c.
︙ | ︙ | |||
272 273 274 275 276 277 278 | struct link_ref *lra = (void *)a; struct link_ref *lrb = (void *)b; return blob_compare(&lra->id, &lrb->id); } /* cmp_footnote_id -- comparison function for footnotes qsort. * Empty IDs sort last (in undetermined order). | | | 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 | struct link_ref *lra = (void *)a; struct link_ref *lrb = (void *)b; return blob_compare(&lra->id, &lrb->id); } /* cmp_footnote_id -- comparison function for footnotes qsort. * Empty IDs sort last (in undetermined order). * Equal IDs are sorted in the order of definition in the source */ static int cmp_footnote_id(const void *fna, const void *fnb){ const struct footnote *a = fna, *b = fnb; const int szA = blob_size(&a->id), szB = blob_size(&b->id); if( szA ){ if( szB ){ int cmp = blob_compare(&a->id, &b->id); if( cmp ) return cmp; |
︙ | ︙ | |||
2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 | const struct mkd_renderer *rndrer /* renderer descriptor (callbacks) */ ){ struct link_ref *lr; struct footnote *fn; size_t i, beg, end = 0; struct render rndr; Blob text = BLOB_INITIALIZER; /* input after the first pass */ /* filling the render structure */ if( !rndrer ) return; rndr.make = *rndrer; rndr.nBlobCache = 0; rndr.iDepth = 0; rndr.refs = empty_blob; | > | 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 | const struct mkd_renderer *rndrer /* renderer descriptor (callbacks) */ ){ struct link_ref *lr; struct footnote *fn; size_t i, beg, end = 0; struct render rndr; Blob text = BLOB_INITIALIZER; /* input after the first pass */ Blob *allNotes = &rndr.notes.all; /* filling the render structure */ if( !rndrer ) return; rndr.make = *rndrer; rndr.nBlobCache = 0; rndr.iDepth = 0; rndr.refs = empty_blob; |
︙ | ︙ | |||
2563 2564 2565 2566 2567 2568 2569 | /* sorting the reference array */ if( blob_size(&rndr.refs) ){ qsort(blob_buffer(&rndr.refs), blob_size(&rndr.refs)/sizeof(struct link_ref), sizeof(struct link_ref), cmp_link_ref_sort); } | | > | > < | < < < < | | > | | | > > > > > | | | < < < < < < < < < < | | < | | | | 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 | /* sorting the reference array */ if( blob_size(&rndr.refs) ){ qsort(blob_buffer(&rndr.refs), blob_size(&rndr.refs)/sizeof(struct link_ref), sizeof(struct link_ref), cmp_link_ref_sort); } rndr.notes.nLbled = COUNT_FOOTNOTES( allNotes ); /* sort footnotes by ID and join duplicates */ if( rndr.notes.nLbled > 1 ){ int nDups = 0; fn = CAST_AS_FOOTNOTES( allNotes ); qsort(fn, rndr.notes.nLbled, sizeof(struct footnote), cmp_footnote_id); /* concatenate footnotes with equal labels */ for(i=0; i<rndr.notes.nLbled ;){ struct footnote *x = fn + i; size_t j = i+1, k = blob_size(&x->text) + 64; while(j<rndr.notes.nLbled && !blob_compare(&x->id, &fn[j].id)){ k += blob_size(&fn[j].text) + 10; j++; nDups++; } if( i+1<j ){ Blob tmp = empty_blob; blob_reserve(&tmp, k); blob_append_string(&tmp, "<ul class='footnote-joined'>\n"); for(k=i; k<j; k++){ struct footnote *y = fn + k; blob_append_string(&tmp, "<li>"); blob_append(&tmp, blob_buffer(&y->text), blob_size(&y->text)); blob_append_string(&tmp, "</li>\n"); /* free memory buffer */ blob_reset(&y->text); if( k!=i ) blob_reset(&y->id); } blob_append_string(&tmp, "</ul>\n"); x->text = tmp; } i = j; } if( nDups ){ /* clean rndr.notes.all from invalidated footnotes */ const int n = rndr.notes.nLbled - nDups; struct Blob filtered = empty_blob; blob_reserve(&filtered, n*sizeof(struct footnote)); for(i=0; i<rndr.notes.nLbled; i++){ if( blob_size(&fn[i].id) ){ blob_append(&filtered, (char*)(fn+i), sizeof(struct footnote)); } } blob_reset( allNotes ); rndr.notes.all = filtered; rndr.notes.nLbled = n; assert( COUNT_FOOTNOTES(allNotes) == rndr.notes.nLbled ); } } fn = CAST_AS_FOOTNOTES( allNotes ); for(i=0; i<rndr.notes.nLbled; i++){ fn[i].index = i; } assert( rndr.notes.nMarks==0 ); /* second pass: actual rendering */ if( rndr.make.prolog ) rndr.make.prolog(ob, rndr.make.opaque); parse_block(ob, &rndr, blob_buffer(&text), blob_size(&text)); if( (blob_size(allNotes) || rndr.notes.misref.nUsed) ){ /* Footnotes must be parsed for the correct discovery of (back)links */ Blob *notes = new_work_buffer( &rndr ); Blob *tmp = new_work_buffer( &rndr ); int nMarks = -1; /* inline notes may get appended to rndr.notes.all while rendering */ while(1){ struct footnote *aNotes; const int N = COUNT_FOOTNOTES( allNotes ); /* make a shallow copy of `origin` */ blob_truncate(notes,0); blob_append(notes, blob_buffer(allNotes), blob_size(allNotes)); aNotes = CAST_AS_FOOTNOTES(notes); qsort(aNotes, N, sizeof(struct footnote), cmp_footnote_sort); if( nMarks == rndr.notes.nMarks ) break; nMarks = rndr.notes.nMarks; for(i=0; i<N; i++){ const int j = aNotes[i].index; struct footnote *x = CAST_AS_FOOTNOTES(allNotes) + j; assert( 0<=j && j<N ); if( x->bRndred || !x->nUsed ) continue; assert( x->iMark > 0 ); assert( blob_size(&x->text) ); blob_truncate(tmp,0); /* `origin` may be altered and extended through this call */ |
︙ | ︙ | |||
2706 2707 2708 2709 2710 2711 2712 | end = blob_size(&rndr.refs)/sizeof(struct link_ref); for(i=0; i<end; i++){ blob_reset(&lr[i].id); blob_reset(&lr[i].link); blob_reset(&lr[i].title); } blob_reset(&rndr.refs); | | | | 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 | end = blob_size(&rndr.refs)/sizeof(struct link_ref); for(i=0; i<end; i++){ blob_reset(&lr[i].id); blob_reset(&lr[i].link); blob_reset(&lr[i].title); } blob_reset(&rndr.refs); fn = CAST_AS_FOOTNOTES( allNotes ); end = COUNT_FOOTNOTES( allNotes ); for(i=0; i<end; i++){ if(blob_size(&fn[i].id)) blob_reset(&fn[i].id); blob_reset(&fn[i].text); } blob_reset(&rndr.notes.all); for(i=0; i<rndr.nBlobCache; i++){ fossil_free(rndr.aBlobCache[i]); } } |