File indexing completed on 2024-04-28 11:21:07
0001 /* markdown: a C implementation of John Gruber's Markdown markup language. 0002 * 0003 * Copyright (C) 2010 David L Parsons. 0004 * The redistribution terms are provided in the COPYRIGHT file that must 0005 * be distributed with this source code. 0006 */ 0007 #include <stdio.h> 0008 #include <string.h> 0009 #include <stdarg.h> 0010 #include <stdlib.h> 0011 #include <time.h> 0012 #include <ctype.h> 0013 0014 #include "config.h" 0015 0016 #include "cstring.h" 0017 #include "markdown.h" 0018 #include "amalloc.h" 0019 0020 0021 /* emmatch: the emphasis mangler that's run after a block 0022 * of html has been generated. 0023 * 0024 * It should create MarkdownTest_1.0 (and _1.0.3) 0025 * compatible emphasis for non-pathological cases 0026 * and it should fail in a standards-compliant way 0027 * when someone attempts to feed it junk. 0028 * 0029 * Emmatching is done after the input has been 0030 * processed into a STRING (f->Q) of text and 0031 * emphasis blocks. After ___mkd_emblock() finishes, 0032 * it truncates f->Q and leaves the rendered paragraph 0033 * if f->out. 0034 */ 0035 0036 0037 /* empair() -- find the NEAREST matching emphasis token (or 0038 * subtoken of a 3+ long emphasis token. 0039 */ 0040 static int 0041 empair(MMIOT *f, int first, int last, int match) 0042 { 0043 0044 int i; 0045 block *begin, *p; 0046 0047 begin = &T(f->Q)[first]; 0048 0049 for (i=first+1; i <= last; i++) { 0050 p = &T(f->Q)[i]; 0051 0052 if ( (p->b_type != bTEXT) && (p->b_count <= 0) ) 0053 continue; /* break? */ 0054 0055 if ( p->b_type == begin->b_type ) { 0056 if ( p->b_count == match ) /* exact match */ 0057 return i; 0058 0059 if ( p->b_count > 2 ) /* fuzzy match */ 0060 return i; 0061 } 0062 } 0063 return 0; 0064 } /* empair */ 0065 0066 0067 /* emfill() -- if an emphasis token has leftover stars or underscores, 0068 * convert them back into character and append them to b_text. 0069 */ 0070 static void 0071 emfill(block *p) 0072 { 0073 int j; 0074 0075 if ( p->b_type == bTEXT ) 0076 return; 0077 0078 for (j=0; j < p->b_count; j++) 0079 EXPAND(p->b_text) = p->b_char; 0080 p->b_count = 0; 0081 } /* emfill */ 0082 0083 0084 static void 0085 emclose(MMIOT *f, int first, int last) 0086 { 0087 int j; 0088 0089 for (j=first+1; j<last-1; j++) 0090 emfill(&T(f->Q)[j]); 0091 } 0092 0093 0094 static struct emtags { 0095 char open[10]; 0096 char close[10]; 0097 int size; 0098 } emtags[] = { { "<em>" , "</em>", 5 }, { "<strong>", "</strong>", 9 } }; 0099 0100 0101 static void emblock(MMIOT*,int,int); 0102 0103 0104 /* emmatch() -- match emphasis for a single emphasis token. 0105 */ 0106 static void 0107 emmatch(MMIOT *f, int first, int last) 0108 { 0109 block *start = &T(f->Q)[first]; 0110 int e, e2, match; 0111 0112 switch (start->b_count) { 0113 case 2: if ( e = empair(f,first,last,match=2) ) 0114 break; 0115 case 1: e = empair(f,first,last,match=1); 0116 break; 0117 case 0: return; 0118 default: 0119 e = empair(f,first,last,1); 0120 e2= empair(f,first,last,2); 0121 0122 if ( e2 >= e ) { 0123 e = e2; 0124 match = 2; 0125 } 0126 else 0127 match = 1; 0128 break; 0129 } 0130 0131 if ( e ) { 0132 /* if we found emphasis to match, match it, recursively call 0133 * emblock to match emphasis inside the new html block, add 0134 * the emphasis markers for the block, then (tail) recursively 0135 * call ourself to match any remaining emphasis on this token. 0136 */ 0137 block *end = &T(f->Q)[e]; 0138 0139 end->b_count -= match; 0140 start->b_count -= match; 0141 0142 emblock(f, first, e); 0143 0144 PREFIX(start->b_text, emtags[match-1].open, emtags[match-1].size-1); 0145 SUFFIX(end->b_post, emtags[match-1].close, emtags[match-1].size); 0146 0147 emmatch(f, first, last); 0148 } 0149 } /* emmatch */ 0150 0151 0152 /* emblock() -- walk a blocklist, attempting to match emphasis 0153 */ 0154 static void 0155 emblock(MMIOT *f, int first, int last) 0156 { 0157 int i; 0158 0159 for ( i = first; i <= last; i++ ) 0160 if ( T(f->Q)[i].b_type != bTEXT ) 0161 emmatch(f, i, last); 0162 emclose(f, first, last); 0163 } /* emblock */ 0164 0165 0166 /* ___mkd_emblock() -- emblock a string of blocks, then concatenate the 0167 * resulting text onto f->out. 0168 */ 0169 void 0170 ___mkd_emblock(MMIOT *f) 0171 { 0172 int i; 0173 block *p; 0174 0175 emblock(f, 0, S(f->Q)-1); 0176 0177 for (i=0; i < S(f->Q); i++) { 0178 p = &T(f->Q)[i]; 0179 emfill(p); 0180 0181 if ( S(p->b_post) ) { SUFFIX(f->out, T(p->b_post), S(p->b_post)); 0182 DELETE(p->b_post); } 0183 if ( S(p->b_text) ) { SUFFIX(f->out, T(p->b_text), S(p->b_text)); 0184 DELETE(p->b_text); } 0185 } 0186 0187 S(f->Q) = 0; 0188 } /* ___mkd_emblock */