Text::Markdown::Discount
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

188 lines
4.1 KiB

  1. /* markdown: a C implementation of John Gruber's Markdown markup language.
  2. *
  3. * Copyright (C) 2010 David L Parsons.
  4. * The redistribution terms are provided in the COPYRIGHT file that must
  5. * be distributed with this source code.
  6. */
  7. #include <stdio.h>
  8. #include <string.h>
  9. #include <stdarg.h>
  10. #include <stdlib.h>
  11. #include <time.h>
  12. #include <ctype.h>
  13. #include "config.h"
  14. #include "cstring.h"
  15. #include "markdown.h"
  16. #include "amalloc.h"
  17. /* emmatch: the emphasis mangler that's run after a block
  18. * of html has been generated.
  19. *
  20. * It should create MarkdownTest_1.0 (and _1.0.3)
  21. * compatable emphasis for non-pathological cases
  22. * and it should fail in a standards-compliant way
  23. * when someone attempts to feed it junk.
  24. *
  25. * Emmatching is done after the input has been
  26. * processed into a STRING (f->Q) of text and
  27. * emphasis blocks. After ___mkd_emblock() finishes,
  28. * it truncates f->Q and leaves the rendered paragraph
  29. * if f->out.
  30. */
  31. /* empair() -- find the NEAREST matching emphasis token (or
  32. * subtoken of a 3+ long emphasis token.
  33. */
  34. static int
  35. empair(MMIOT *f, int first, int last, int match)
  36. {
  37. int i;
  38. block *begin, *p;
  39. begin = &T(f->Q)[first];
  40. for (i=first+1; i <= last; i++) {
  41. p = &T(f->Q)[i];
  42. if ( (p->b_type != bTEXT) && (p->b_count <= 0) )
  43. continue; /* break? */
  44. if ( p->b_type == begin->b_type ) {
  45. if ( p->b_count == match ) /* exact match */
  46. return i;
  47. if ( p->b_count > 2 ) /* fuzzy match */
  48. return i;
  49. }
  50. }
  51. return 0;
  52. } /* empair */
  53. /* emfill() -- if an emphasis token has leftover stars or underscores,
  54. * convert them back into character and append them to b_text.
  55. */
  56. static void
  57. emfill(block *p)
  58. {
  59. int j;
  60. if ( p->b_type == bTEXT )
  61. return;
  62. for (j=0; j < p->b_count; j++)
  63. EXPAND(p->b_text) = p->b_char;
  64. p->b_count = 0;
  65. } /* emfill */
  66. static void
  67. emclose(MMIOT *f, int first, int last)
  68. {
  69. int j;
  70. for (j=first+1; j<last-1; j++)
  71. emfill(&T(f->Q)[j]);
  72. }
  73. static struct emtags {
  74. char open[10];
  75. char close[10];
  76. int size;
  77. } emtags[] = { { "<em>" , "</em>", 5 }, { "<strong>", "</strong>", 9 } };
  78. static void emblock(MMIOT*,int,int);
  79. /* emmatch() -- match emphasis for a single emphasis token.
  80. */
  81. static void
  82. emmatch(MMIOT *f, int first, int last)
  83. {
  84. block *start = &T(f->Q)[first];
  85. int e, e2, match;
  86. switch (start->b_count) {
  87. case 2: if ( e = empair(f,first,last,match=2) )
  88. break;
  89. case 1: e = empair(f,first,last,match=1);
  90. break;
  91. case 0: return;
  92. default:
  93. e = empair(f,first,last,1);
  94. e2= empair(f,first,last,2);
  95. if ( e2 >= e ) {
  96. e = e2;
  97. match = 2;
  98. }
  99. else
  100. match = 1;
  101. break;
  102. }
  103. if ( e ) {
  104. /* if we found emphasis to match, match it, recursively call
  105. * emblock to match emphasis inside the new html block, add
  106. * the emphasis markers for the block, then (tail) recursively
  107. * call ourself to match any remaining emphasis on this token.
  108. */
  109. block *end = &T(f->Q)[e];
  110. end->b_count -= match;
  111. start->b_count -= match;
  112. emblock(f, first, e);
  113. PREFIX(start->b_text, emtags[match-1].open, emtags[match-1].size-1);
  114. SUFFIX(end->b_post, emtags[match-1].close, emtags[match-1].size);
  115. emmatch(f, first, last);
  116. }
  117. } /* emmatch */
  118. /* emblock() -- walk a blocklist, attempting to match emphasis
  119. */
  120. static void
  121. emblock(MMIOT *f, int first, int last)
  122. {
  123. int i;
  124. for ( i = first; i <= last; i++ )
  125. if ( T(f->Q)[i].b_type != bTEXT )
  126. emmatch(f, i, last);
  127. emclose(f, first, last);
  128. } /* emblock */
  129. /* ___mkd_emblock() -- emblock a string of blocks, then concatenate the
  130. * resulting text onto f->out.
  131. */
  132. void
  133. ___mkd_emblock(MMIOT *f)
  134. {
  135. int i;
  136. block *p;
  137. emblock(f, 0, S(f->Q)-1);
  138. for (i=0; i < S(f->Q); i++) {
  139. p = &T(f->Q)[i];
  140. emfill(p);
  141. if ( S(p->b_post) ) { SUFFIX(f->out, T(p->b_post), S(p->b_post));
  142. DELETE(p->b_post); }
  143. if ( S(p->b_text) ) { SUFFIX(f->out, T(p->b_text), S(p->b_text));
  144. DELETE(p->b_text); }
  145. }
  146. S(f->Q) = 0;
  147. } /* ___mkd_emblock */