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