1 /* markdown: a C implementation of John Gruber's Markdown markup language.
2  *
3  * Copyright (C) 2007 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 "markdown.h"
9 #include "cstring.h"
10 #include "amalloc.h"
11 
12 struct frame {
13     int indent;
14     char c;
15 };
16 
17 typedef STRING(struct frame) Stack;
18 
19 static char *
Pptype(int typ)20 Pptype(int typ)
21 {
22     switch (typ) {
23     case WHITESPACE: return "whitespace";
24     case CODE      : return "code";
25     case QUOTE     : return "quote";
26     case MARKUP    : return "markup";
27     case HTML      : return "html";
28     case DL        : return "dl";
29     case UL        : return "ul";
30     case OL        : return "ol";
31     case LISTITEM  : return "item";
32     case HDR       : return "header";
33     case HR        : return "hr";
34     case TABLE     : return "table";
35     case SOURCE    : return "source";
36     case STYLE     : return "style";
37     default        : return "mystery node!";
38     }
39 }
40 
41 static void
pushpfx(int indent,char c,Stack * sp)42 pushpfx(int indent, char c, Stack *sp)
43 {
44     struct frame *q = &EXPAND(*sp);
45 
46     q->indent = indent;
47     q->c = c;
48 }
49 
50 
51 static void
poppfx(Stack * sp)52 poppfx(Stack *sp)
53 {
54     S(*sp)--;
55 }
56 
57 
58 static void
changepfx(Stack * sp,char c)59 changepfx(Stack *sp, char c)
60 {
61     char ch;
62 
63     if ( !S(*sp) ) return;
64 
65     ch = T(*sp)[S(*sp)-1].c;
66 
67     if ( ch == '+' || ch == '|' )
68 	T(*sp)[S(*sp)-1].c = c;
69 }
70 
71 
72 static void
printpfx(Stack * sp,FILE * f)73 printpfx(Stack *sp, FILE *f)
74 {
75     int i;
76     char c;
77 
78     if ( !S(*sp) ) return;
79 
80     c = T(*sp)[S(*sp)-1].c;
81 
82     if ( c == '+' || c == '-' ) {
83 	fprintf(f, "--%c", c);
84 	T(*sp)[S(*sp)-1].c = (c == '-') ? ' ' : '|';
85     }
86     else
87 	for ( i=0; i < S(*sp); i++ ) {
88 	    if ( i )
89 		fprintf(f, "  ");
90 	    fprintf(f, "%*s%c", T(*sp)[i].indent + 2, " ", T(*sp)[i].c);
91 	    if ( T(*sp)[i].c == '`' )
92 		T(*sp)[i].c = ' ';
93 	}
94     fprintf(f, "--");
95 }
96 
97 
98 static void
dumptree(Paragraph * pp,Stack * sp,FILE * f)99 dumptree(Paragraph *pp, Stack *sp, FILE *f)
100 {
101     int count;
102     Line *p;
103     int d;
104     static char *Begin[] = { 0, "P", "center" };
105 
106     while ( pp ) {
107 	if ( !pp->next )
108 	    changepfx(sp, '`');
109 	printpfx(sp, f);
110 
111 	if ( pp->typ == HDR )
112 	    d += fprintf(f, "[h%d", pp->hnumber);
113 	else
114 	    d = fprintf(f, "[%s", Pptype(pp->typ));
115 	if ( pp->ident )
116 	    d += fprintf(f, " %s", pp->ident);
117 
118 #ifdef GITHUB_CHECKBOX
119 	if ( pp->flags )
120 	    d += fprintf(f, " %x", pp->flags);
121 #endif
122 
123 	if ( pp->align > 1 )
124 	    d += fprintf(f, ", <%s>", Begin[pp->align]);
125 
126 	for (count=0, p=pp->text; p; ++count, (p = p->next) )
127 	    ;
128 
129 	if ( count )
130 	    d += fprintf(f, ", %d line%s", count, (count==1)?"":"s");
131 
132 	d += fprintf(f, "]");
133 
134 	if ( pp->down ) {
135 	    pushpfx(d, pp->down->next ? '+' : '-', sp);
136 	    dumptree(pp->down, sp, f);
137 	    poppfx(sp);
138 	}
139 	else fputc('\n', f);
140 	pp = pp->next;
141     }
142 }
143 
144 
145 int
mkd_dump(Document * doc,FILE * out,mkd_flag_t flags,char * title)146 mkd_dump(Document *doc, FILE *out, mkd_flag_t flags, char *title)
147 {
148     Stack stack;
149 
150     if (mkd_compile(doc, flags) ) {
151 
152 	CREATE(stack);
153 	pushpfx(fprintf(out, "%s", title), doc->code->next ? '+' : '-', &stack);
154 	dumptree(doc->code, &stack, out);
155 	DELETE(stack);
156 
157 	return 0;
158     }
159     return -1;
160 }
161