Fossil

Check-in [2636e224]
Login

Check-in [2636e224]

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Minor code refactoring.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | markdown-footnotes
Files: files | file ages | folders
SHA3-256: 2636e2245e7ed14fb529cd4ae63526465984b9b763f26bb27d1b5543186905ef
User & Date: george 2022-02-04 19:47:39
Context
2022-02-04
23:07
Handle misreferences: a reference to undefined footnote. ... (check-in: 28e6a9cd user: george tags: markdown-footnotes)
19:47
Minor code refactoring. ... (check-in: 2636e224 user: george tags: markdown-footnotes)
19:24
Automatically render a horizontal rule before the list of footnotes. If desired a particular skin can hide it using CSS selector "hr.footnotes-separator". ... (check-in: 6807b434 user: george tags: markdown-footnotes)
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/markdown.c.

169
170
171
172
173
174
175

176
177
178

179
180
181
182
183
184
185
  struct mkd_renderer make;
  struct Blob refs;
  char_trigger active_char[256];
  int iDepth;                    /* Depth of recursion */
  int nBlobCache;                /* Number of entries in aBlobCache */
  struct Blob *aBlobCache[20];   /* Cache of Blobs available for reuse */


  struct Blob notes;  /* array of footnotes */
  int nLabeled;       /* number of footnotes found by the first pass */
  int iNotesCount;    /* count distinct indices found in the second pass */

};

/* html_tag -- structure for quick HTML tag search (inspired from discount) */
struct html_tag {
  const char *text;
  int size;
};







>
|
|
|
>







169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
  struct mkd_renderer make;
  struct Blob refs;
  char_trigger active_char[256];
  int iDepth;                    /* Depth of recursion */
  int nBlobCache;                /* Number of entries in aBlobCache */
  struct Blob *aBlobCache[20];   /* Cache of Blobs available for reuse */

  struct {
    Blob all;    /* array of footnotes */
    int nLbled;  /* number of labeled footnotes found during the first pass */
    int nMarks;  /* count distinct indices found in the second pass */
  } notes;
};

/* html_tag -- structure for quick HTML tag search (inspired from discount) */
struct html_tag {
  const char *text;
  int size;
};
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
  struct render *rndr,
  const char *data,
  size_t size
){
  struct footnote *fn = NULL;
  struct Blob *id = new_work_buffer(rndr);
  if( build_ref_id(id, data, size)<0 ) goto cleanup;
  fn = bsearch(id, blob_buffer(&rndr->notes),
               rndr->nLabeled,
               sizeof (struct footnote),
               cmp_link_ref);
  if( !fn ) goto cleanup;

  if( fn->index == 0 ){  /* the first reference to the footnote */
    assert( fn->nUsed == 0 );
    fn->index = ++(rndr->iNotesCount);
  }
  fn->nUsed++;
  assert( fn->index > 0 );
  assert( fn->nUsed > 0 );
cleanup:
  release_work_buffer( rndr, id );
  return fn;
}
/* Adds unlabeled footnote to the rndr.
 * If text is blank then returns 0,
 * otherwise returns the address of the added footnote. */
static inline const struct footnote* add_inline_footnote(
  struct render *rndr,
  const char *text,
  size_t size
){
  struct footnote fn = { empty_blob, empty_blob, 0, 0 };
  while(size && (*text==' ' || *text=='\t')){ text++; size--; }
  if(!size) return 0;
  fn.index = ++(rndr->iNotesCount);
  fn.nUsed = 1;
  assert( fn.index > 0 );
  blob_append(&fn.text, text, size);
  blob_append(&rndr->notes, (char *)&fn, sizeof fn);
  return (struct footnote*)( blob_buffer(&rndr->notes)
                            +( blob_size(&rndr->notes)-sizeof fn ));
}

/* Return the offset of the matching closing bracket or 0 if not found.
 * begin[0] must be either '[' or '('          */
static inline size_t matching_bracket_offset(
  const char* begin,
  const char* end







|
|






|



















|



|
|
|







1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
  struct render *rndr,
  const char *data,
  size_t size
){
  struct footnote *fn = NULL;
  struct Blob *id = new_work_buffer(rndr);
  if( build_ref_id(id, data, size)<0 ) goto cleanup;
  fn = bsearch(id, blob_buffer(&rndr->notes.all),
               rndr->notes.nLbled,
               sizeof (struct footnote),
               cmp_link_ref);
  if( !fn ) goto cleanup;

  if( fn->index == 0 ){  /* the first reference to the footnote */
    assert( fn->nUsed == 0 );
    fn->index = ++(rndr->notes.nMarks);
  }
  fn->nUsed++;
  assert( fn->index > 0 );
  assert( fn->nUsed > 0 );
cleanup:
  release_work_buffer( rndr, id );
  return fn;
}
/* Adds unlabeled footnote to the rndr.
 * If text is blank then returns 0,
 * otherwise returns the address of the added footnote. */
static inline const struct footnote* add_inline_footnote(
  struct render *rndr,
  const char *text,
  size_t size
){
  struct footnote fn = { empty_blob, empty_blob, 0, 0 };
  while(size && (*text==' ' || *text=='\t')){ text++; size--; }
  if(!size) return 0;
  fn.index = ++(rndr->notes.nMarks);
  fn.nUsed = 1;
  assert( fn.index > 0 );
  blob_append(&fn.text, text, size);
  blob_append(&rndr->notes.all, (char *)&fn, sizeof fn);
  return (struct footnote*)( blob_buffer(&rndr->notes.all)
                            +( blob_size(&rndr->notes.all)-sizeof fn ));
}

/* Return the offset of the matching closing bracket or 0 if not found.
 * begin[0] must be either '[' or '('          */
static inline size_t matching_bracket_offset(
  const char* begin,
  const char* end
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466

  /* filling the render structure */
  if( !rndrer ) return;
  rndr.make = *rndrer;
  rndr.nBlobCache = 0;
  rndr.iDepth = 0;
  rndr.refs  = empty_blob;
  rndr.notes = empty_blob;
  rndr.iNotesCount = 0;
  for(i=0; i<256; i++) rndr.active_char[i] = 0;
  if( (rndr.make.emphasis
    || rndr.make.double_emphasis
    || rndr.make.triple_emphasis)
   && rndr.make.emph_chars
  ){
    for(i=0; rndr.make.emph_chars[i]; i++){







|
|







2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468

  /* filling the render structure */
  if( !rndrer ) return;
  rndr.make = *rndrer;
  rndr.nBlobCache = 0;
  rndr.iDepth = 0;
  rndr.refs  = empty_blob;
  rndr.notes.all = empty_blob;
  rndr.notes.nMarks = 0;
  for(i=0; i<256; i++) rndr.active_char[i] = 0;
  if( (rndr.make.emphasis
    || rndr.make.double_emphasis
    || rndr.make.triple_emphasis)
   && rndr.make.emph_chars
  ){
    for(i=0; rndr.make.emph_chars[i]; i++){
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
  /* first pass: iterate over lines looking for references,
   * copying everything else into "text" */
  beg = 0;
  for(const size_t size = blob_size(ib); beg<size ;){
    const char* const data = blob_buffer(ib);
    if( is_ref(data, beg, size, &end, &rndr.refs) ){
      beg = end;
    }else if(is_footnote(data, beg, size, &end, &rndr.notes)){
      /* FIXME: fossil_print("\nfootnote found at %i\n", beg); */
      beg = end;
    }else{ /* skipping to the next line */
      end = beg;
      while( end<size && data[end]!='\n' && data[end]!='\r' ){
        end += 1;
      }
      /* adding the line body if present */
      if( end>beg ) blob_append(&text, data + beg, end - beg);
      while( end<size && (data[end]=='\n' || data[end]=='\r') ){
        /* add one \n per newline */
        if( data[end]=='\n' || (end+1<size && data[end+1]!='\n') ){
          blob_append_char(&text, '\n');
        }
        end += 1;
      }
      beg = end;
    }
  }
  assert( rndr.iNotesCount==0 );
  /* 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.nLabeled = COUNT_FOOTNOTES(&rndr.notes);
  /* sorting the footnotes array by id */
  if( rndr.nLabeled ){
    qsort(blob_buffer(&rndr.notes), rndr.nLabeled, sizeof(struct footnote),
          cmp_link_ref_sort);
  }

  /* 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));

  fn = (struct footnote*)blob_buffer(&rndr.notes);
  if(rndr.iNotesCount && rndr.make.footnote_item && rndr.make.footnotes){
    Blob * one_item  = new_work_buffer(&rndr);
    Blob * all_items = new_work_buffer(&rndr);
    qsort( fn, COUNT_FOOTNOTES(&rndr.notes), sizeof(struct footnote),
           cmp_footnote_sort /* sort footnotes by index */ );
    blob_reset( all_items );
    for(i=0; i<rndr.iNotesCount; i++){
      assert( fn[i].index == i+1 );

      blob_reset( one_item );
      parse_inline( one_item, &rndr, blob_buffer(&fn[i].text),
                    blob_size(&fn[i].text));
      rndr.make.footnote_item( all_items, one_item, i+1, fn[i].nUsed, rndr.make.opaque);
    }







|



















|







|

|
|
|






|
|


|


|







2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
  /* first pass: iterate over lines looking for references,
   * copying everything else into "text" */
  beg = 0;
  for(const size_t size = blob_size(ib); beg<size ;){
    const char* const data = blob_buffer(ib);
    if( is_ref(data, beg, size, &end, &rndr.refs) ){
      beg = end;
    }else if(is_footnote(data, beg, size, &end, &rndr.notes.all)){
      /* FIXME: fossil_print("\nfootnote found at %i\n", beg); */
      beg = end;
    }else{ /* skipping to the next line */
      end = beg;
      while( end<size && data[end]!='\n' && data[end]!='\r' ){
        end += 1;
      }
      /* adding the line body if present */
      if( end>beg ) blob_append(&text, data + beg, end - beg);
      while( end<size && (data[end]=='\n' || data[end]=='\r') ){
        /* add one \n per newline */
        if( data[end]=='\n' || (end+1<size && data[end+1]!='\n') ){
          blob_append_char(&text, '\n');
        }
        end += 1;
      }
      beg = end;
    }
  }
  assert( rndr.notes.nMarks==0 );
  /* 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(&rndr.notes.all);
  /* sorting the footnotes array by id */
  if( rndr.notes.nLbled ){
    qsort(blob_buffer(&rndr.notes.all), rndr.notes.nLbled,
          sizeof(struct footnote), cmp_link_ref_sort);
  }

  /* 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));

  fn = (struct footnote*)blob_buffer(&rndr.notes.all);
  if(rndr.notes.nMarks && rndr.make.footnote_item && rndr.make.footnotes){
    Blob * one_item  = new_work_buffer(&rndr);
    Blob * all_items = new_work_buffer(&rndr);
    qsort( fn, COUNT_FOOTNOTES(&rndr.notes.all), sizeof(struct footnote),
           cmp_footnote_sort /* sort footnotes by index */ );
    blob_reset( all_items );
    for(i=0; i<rndr.notes.nMarks; i++){
      assert( fn[i].index == i+1 );

      blob_reset( one_item );
      parse_inline( one_item, &rndr, blob_buffer(&fn[i].text),
                    blob_size(&fn[i].text));
      rndr.make.footnote_item( all_items, one_item, i+1, fn[i].nUsed, rndr.make.opaque);
    }
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
  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);
  end = COUNT_FOOTNOTES(&rndr.notes);
  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);
  for(i=0; i<rndr.nBlobCache; i++){
    fossil_free(rndr.aBlobCache[i]);
  }
}







|




|




2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
  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);
  end = COUNT_FOOTNOTES(&rndr.notes.all);
  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]);
  }
}