Exemple #1
0
static Paragraph *
fencedcodeblock(ParagraphRoot *d, Line **ptr)
{
    Line *first, *r;
    Paragraph *ret;

    first = (*ptr);
    
    /* don't allow zero-length code fences
     */
    if ( (first->next == 0) || iscodefence(first->next, first->count, 0) )
	return 0;

    /* find the closing fence, discard the fences,
     * return a Paragraph with the contents
     */
    for ( r = first; r && r->next; r = r->next )
	if ( iscodefence(r->next, first->count, first->kind) ) {
	    (*ptr) = r->next->next;
	    ret = Pp(d, first->next, CODE);
      if (S(first->text) - first->count > 0) {
        char *lang_attr = T(first->text) + first->count;
        while ( *lang_attr != 0 && *lang_attr == ' ' ) lang_attr++;
        ret->lang = strdup(lang_attr);
      }
      else {
        ret->lang = 0;
      }
	    ___mkd_freeLine(first);
	    ___mkd_freeLine(r->next);
	    r->next = 0;
	    return ret;
	}
    return 0;
}
Exemple #2
0
static Paragraph *
fencedcodeblock(ParagraphRoot *d, Line **ptr)
{
    Line *first, *r;
    Paragraph *ret;

    first = (*ptr);
    
    /* don't allow zero-length code fences
     */
    if ( (first->next == 0) || iscodefence(first->next, first->count) )
	return 0;

    /* find the closing fence, discard the fences,
     * return a Paragraph with the contents
     */
    for ( r = first; r && r->next; r = r->next )
	if ( iscodefence(r->next, first->count) ) {
	    (*ptr) = r->next->next;
	    ret = Pp(d, first->next, CODE);
	    ___mkd_freeLine(first);
	    ___mkd_freeLine(r->next);
	    r->next = 0;
	    return ret;
	}
    return 0;
}
/* free a list of lines
 */
void
___mkd_freeLines(Discount::Line *p)
{
    if (p->next)
	 ___mkd_freeLines(p->next);
    ___mkd_freeLine(p);
}
Exemple #4
0
/* free a list of lines
 */
void
___mkd_freeLines(Line *p)
{
    if (p->next)
	 ___mkd_freeLines(p->next);
    ___mkd_freeLine(p);
}
/* clean up everything allocated in __mkd_compile()
 */
void
mkd_cleanup(Document *doc)
{
    if ( doc && (doc->magic == VALID_DOCUMENT) ) {
	if ( doc->ctx ) {
	    ___mkd_freemmiot(doc->ctx, 0);
	    free(doc->ctx);
	}

	if ( doc->code) ___mkd_freeParagraph(doc->code);
	if ( doc->title) ___mkd_freeLine(doc->title);
	if ( doc->author) ___mkd_freeLine(doc->author);
	if ( doc->date) ___mkd_freeLine(doc->date);
	if ( T(doc->content) ) ___mkd_freeLines(T(doc->content));
	memset(doc, 0, sizeof doc[0]);
	free(doc);
    }
}
Exemple #6
0
static Line*
consume(Line *ptr, int *eaten)
{
    Line *next;
    int blanks=0;

    for (; ptr && blankline(ptr); ptr = next, blanks++ ) {
	next = ptr->next;
	___mkd_freeLine(ptr);
    }
    if ( ptr ) *eaten = blanks;
    return ptr;
}
Exemple #7
0
/*
 * accumulate a blockquote.
 *
 * one sick horrible thing about blockquotes is that even though
 * it just takes ^> to start a quote, following lines, if quoted,
 * assume that the prefix is ``> ''.   This means that code needs
 * to be indented *5* spaces from the leading '>', but *4* spaces
 * from the start of the line.   This does not appear to be 
 * documented in the reference implementation, but it's the
 * way the markdown sample web form at Daring Fireball works.
 */
static Line *
quoteblock(Paragraph *p, DWORD flags)
{
    Line *t, *q;
    int qp;

    for ( t = p->text; t ; t = q ) {
	if ( isquote(t) ) {
	    /* clip leading spaces */
	    for (qp = 0; T(t->text)[qp] != '>'; qp ++)
		/* assert: the first nonblank character on this line
		 * will be a >
		 */;
	    /* clip '>' */
	    qp++;
	    /* clip next space, if any */
	    if ( T(t->text)[qp] == ' ' )
		qp++;
	    CLIP(t->text, 0, qp);
	    UNCHECK(t);
	    t->dle = mkd_firstnonblank(t);
	}

	q = skipempty(t->next);

	if ( (q == 0) || ((q != t->next) && (!isquote(q) || isdivmarker(q,1,flags))) ) {
	    ___mkd_freeLineRange(t, q);
	    t = q;
	    break;
	}
    }
    if ( isdivmarker(p->text,0,flags) ) {
	char *prefix = "class";
	int i;
	
	q = p->text;
	p->text = p->text->next;

	if ( (i = szmarkerclass(1+T(q->text))) == 3 )
	    /* and this would be an "%id:" prefix */
	    prefix="id";
	    
	if ( p->ident = malloc(4+strlen(prefix)+S(q->text)) )
	    sprintf(p->ident, "%s=\"%.*s\"", prefix, S(q->text)-(i+2),
						     T(q->text)+(i+1) );

	___mkd_freeLine(q);
    }
    return t;
}
Exemple #8
0
static Line *
headerblock(Paragraph *pp, int htyp)
{
    Line *ret = 0;
    Line *p = pp->text;
    int i, j;

    switch (htyp) {
    case SETEXT:
	    /* p->text is header, p->next->text is -'s or ='s
	     */
	    pp->hnumber = (T(p->next->text)[0] == '=') ? 1 : 2;
	    
	    ret = p->next->next;
	    ___mkd_freeLine(p->next);
	    p->next = 0;
	    break;

    case ETX:
	    /* p->text is ###header###, so we need to trim off
	     * the leading and trailing `#`'s
	     */

	    for (i=0; (T(p->text)[i] == T(p->text)[0]) && (i < S(p->text)-1)
						       && (i < 6); i++)
		;

	    pp->hnumber = i;

	    while ( (i < S(p->text)) && isspace(T(p->text)[i]) )
		++i;

	    CLIP(p->text, 0, i);
	    UNCHECK(p);

	    for (j=S(p->text); (j > 1) && (T(p->text)[j-1] == '#'); --j)
		;

	    while ( j && isspace(T(p->text)[j-1]) )
		--j;

	    S(p->text) = j;

	    ret = p->next;
	    p->next = 0;
	    break;
    }
    return ret;
}
Exemple #9
0
/*
 * break a collection of markdown input into
 * blocks of lists, code, html, and text to
 * be marked up.
 */
static Paragraph *
compile(Line *ptr, int toplevel, MMIOT *f)
{
    ParagraphRoot d = { 0, 0 };
    Paragraph *p = 0;
    Line *r;
    int para = toplevel;
    int blocks = 0;
    int hdr_type, list_type, list_class, indent;

    ptr = consume(ptr, &para);

    while ( ptr ) {
	if ( iscode(ptr) ) {
	    p = Pp(&d, ptr, CODE);
	    
	    if ( f->flags & MKD_1_COMPAT) {
		/* HORRIBLE STANDARDS KLUDGE: the first line of every block
		 * has trailing whitespace trimmed off.
		 */
		___mkd_tidy(&p->text->text);
	    }
	    
	    ptr = codeblock(p);
	}
#if WITH_FENCED_CODE
	else if ( iscodefence(ptr,3,0) && (p=fencedcodeblock(&d, &ptr)) )
	    /* yay, it's already done */ ;
#endif
	else if ( ishr(ptr) ) {
	    p = Pp(&d, 0, HR);
	    r = ptr;
	    ptr = ptr->next;
	    ___mkd_freeLine(r);
	}
	else if ( list_class = islist(ptr, &indent, f->flags, &list_type) ) {
	    if ( list_class == DL ) {
		p = Pp(&d, ptr, DL);
		ptr = definition_block(p, indent, f, list_type);
	    }
	    else {
		p = Pp(&d, ptr, list_type);
		ptr = enumerated_block(p, indent, f, list_class);
	    }
	}
	else if ( isquote(ptr) ) {
	    p = Pp(&d, ptr, QUOTE);
	    ptr = quoteblock(p, f->flags);
	    p->down = compile(p->text, 1, f);
	    p->text = 0;
	}
	else if ( ishdr(ptr, &hdr_type) ) {
	    p = Pp(&d, ptr, HDR);
	    ptr = headerblock(p, hdr_type);
	}
	else {
	    p = Pp(&d, ptr, MARKUP);
	    ptr = textblock(p, toplevel, f->flags);
	    /* tables are a special kind of paragraph */
	    if ( actually_a_table(f, p->text) )
		p->typ = TABLE;
	}

	if ( (para||toplevel) && !p->align )
	    p->align = PARA;

	blocks++;
	para = toplevel || (blocks > 1);
	ptr = consume(ptr, &para);

	if ( para && !p->align )
	    p->align = PARA;

    }
    return T(d);
}
Exemple #10
0
/*
 * add a new (image or link) footnote to the footnote table
 */
static Line*
addfootnote(Line *p, MMIOT* f)
{
    int j, i;
    int c;
    Line *np = p->next;

    Footnote *foot = &EXPAND(f->footnotes->note);
    
    CREATE(foot->tag);
    CREATE(foot->link);
    CREATE(foot->title);
    foot->flags = foot->height = foot->width = 0;

    for (j=i=p->dle+1; T(p->text)[j] != ']'; j++)
	EXPAND(foot->tag) = T(p->text)[j];

    EXPAND(foot->tag) = 0;
    S(foot->tag)--;
    j = nextnonblank(p, j+2);

    if ( (f->flags & MKD_EXTRA_FOOTNOTE) && (T(foot->tag)[0] == '^') ) {
	/* need to consume all lines until non-indented block? */
	while ( j < S(p->text) )
	    EXPAND(foot->title) = T(p->text)[j++];
	goto skip_to_end;
    }

    while ( (j < S(p->text)) && !isspace(T(p->text)[j]) )
	EXPAND(foot->link) = T(p->text)[j++];
    EXPAND(foot->link) = 0;
    S(foot->link)--;
    j = nextnonblank(p,j);

    if ( T(p->text)[j] == '=' ) {
	sscanf(T(p->text)+j, "=%dx%d", &foot->width, &foot->height);
	while ( (j < S(p->text)) && !isspace(T(p->text)[j]) )
	    ++j;
	j = nextnonblank(p,j);
    }


    if ( (j >= S(p->text)) && np && np->dle && tgood(T(np->text)[np->dle]) ) {
	___mkd_freeLine(p);
	p = np;
	np = p->next;
	j = p->dle;
    }

    if ( (c = tgood(T(p->text)[j])) ) {
	/* Try to take the rest of the line as a comment; read to
	 * EOL, then shrink the string back to before the final
	 * quote.
	 */
	++j;	/* skip leading quote */

	while ( j < S(p->text) )
	    EXPAND(foot->title) = T(p->text)[j++];

	while ( S(foot->title) && T(foot->title)[S(foot->title)-1] != c )
	    --S(foot->title);
	if ( S(foot->title) )	/* skip trailing quote */
	    --S(foot->title);
	EXPAND(foot->title) = 0;
	--S(foot->title);
    }

skip_to_end:
    ___mkd_freeLine(p);
    return np;
}
Exemple #11
0
/*
 * break a collection of markdown input into
 * blocks of lists, code, html, and text to
 * be marked up.
 */
static Paragraph *
compile(Line *ptr, int toplevel, MMIOT *f)
{
    ParagraphRoot d = { 0, 0 };
    Paragraph *p = 0;
    Line *r;
    int para = toplevel;
    int blocks = 0;
    int hdr_type, list_type, list_class, indent;

    ptr = consume(ptr, &para);

    while ( ptr ) {
	if ( iscode(ptr) ) {
	    p = Pp(&d, ptr, CODE);
	    
	    if ( f->flags & MKD_1_COMPAT) {
		/* HORRIBLE STANDARDS KLUDGE: the first line of every block
		 * has trailing whitespace trimmed off.
		 */
		___mkd_tidy(&p->text->text);
	    }
	    
	    ptr = codeblock(p);
	}
	else if ( ishr(ptr) ) {
	    p = Pp(&d, 0, HR);
	    r = ptr;
	    ptr = ptr->next;
	    ___mkd_freeLine(r);
	}
	else if (( list_class = islist(ptr, &indent, f->flags, &list_type) )) {
	    if ( list_class == DL ) {
		p = Pp(&d, ptr, DL);
		ptr = definition_block(p, indent, f, list_type);
	    }
	    else {
		p = Pp(&d, ptr, list_type);
		ptr = enumerated_block(p, indent, f, list_class);
	    }
	}
	else if ( isquote(ptr) ) {
	    p = Pp(&d, ptr, QUOTE);
	    ptr = quoteblock(p, f->flags);
	    p->down = compile(p->text, 1, f);
	    p->text = 0;
	}
	else if ( ishdr(ptr, &hdr_type) ) {
	    p = Pp(&d, ptr, HDR);
	    ptr = headerblock(p, hdr_type);
	}
	else if ( istable(ptr) && !(f->flags & (MKD_STRICT|MKD_NOTABLES)) ) {
	    p = Pp(&d, ptr, TABLE);
	    ptr = tableblock(p);
	}
	else {
	    p = Pp(&d, ptr, MARKUP);
	    ptr = textblock(p, toplevel, f->flags);
	}

	if ( (para||toplevel) && !p->align )
	    p->align = PARA;

	blocks++;
	para = toplevel || (blocks > 1);
	ptr = consume(ptr, &para);

	if ( para && !p->align )
	    p->align = PARA;

    }
    return T(d);
}