added header detection + test
[smdp.git] / markdown_io.c
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 #include "include/cstring.h"
5 #include "include/markdown.h"
6
7 document_t *markdown_load(FILE *input) {
8
9     int c = 0, i = 0, bits = 0;
10
11     document_t *doc;
12     page_t *page;
13     line_t *line;
14     cstring_t *text;
15
16     doc = new_document();
17     page = new_page();
18     doc->page = page;
19     text = cstring_init();
20
21     while ((c = fgetc(input)) != EOF) {
22         if(c == '\n') {
23
24             // markdown analyse
25             bits = markdown_analyse(text);
26
27             // if text is markdown hr
28             if(CHECK_BIT(bits, IS_HR)) {
29
30                 // clear text
31                 (text->reset)(text);
32                 // create next page
33                 page = next_page(page);
34
35             } else {
36
37                 // if page ! has line
38                 if(!page->line) {
39
40                     // create new line
41                     line = new_line();
42                     page->line = line;
43
44                 } else {
45
46                     // create next line
47                     line = next_line(line);
48
49                 }
50
51                 // add text to line
52                 line->text = text;
53
54                 // add bits to line
55                 line->bits = bits;
56
57                 // calc offset
58                 line->offset = next_nonblank(text, 0);
59
60                 // new text
61                 text = cstring_init();
62             }
63
64         } else if(c == '\t') {
65
66             // expand tab to spaces
67             for (i = 0;  i <= 4;  i++)
68                 (text->expand)(text, ' ');
69
70         } else if(isprint(c) || isspace(c) || is_utf8(c)) {
71
72             // add char to line
73             (text->expand)(text, c);
74         }
75     }
76
77     // detect header
78     line = doc->page->line;
79     if(line && line->text->size > 0 && line->text->text[0] == '%') {
80
81         // assign header to document
82         doc->header = line;
83
84         // find first non-header line
85         while(line->text->size > 0 && line->text->text[0] == '%') {
86             line = line->next;
87         }
88
89         // split linked list
90         line->prev->next = (void*)0;
91         line->prev = (void*)0;
92
93         // remove header lines from page
94         doc->page->line = line;
95     }
96
97     return doc;
98 }
99
100 int markdown_analyse(cstring_t *text) {
101     int i = 0, bits = 0,
102         offset = 0, eol = 0,
103         equals = 0, hashes = 0, stars = 0, minus = 0, plus = 0,
104         spaces = 0, other = 0;
105
106     // count leading spaces
107     offset = next_nonblank(text, 0);
108
109     // IS_CODE
110     if(offset >= 4) {
111         SET_BIT(bits, IS_CODE);
112         return bits;
113     }
114
115     // strip trailing spaces
116     for(eol = text->size; eol > offset && isspace(text->text[eol - 1]); eol--);
117
118     for(i = offset; i < eol; i++) {
119
120         switch(text->text[i]) {
121             case '=': equals++; break;
122             case '#': hashes++; break;
123             case '*': stars++; break;
124             case '-': minus++; break;
125             case '+': plus++; break;
126             case ' ': spaces++; break;
127             default: other++; break;
128         }
129     }
130
131     // IS_HR
132     if((minus >= 3 && equals + hashes + stars + plus == 0) ||
133        (stars >= 3 && equals + hashes + minus + plus == 0)) {
134
135         SET_BIT(bits, IS_HR);
136         return bits;
137     }
138
139     //TODO all the other markdown tags
140
141     return bits;
142 }
143
144 int is_utf8(char ch) {
145     return (ch & 0x80);
146 }
147
148 int next_nonblank(cstring_t *text, int i) {
149     while ((i < text->size) && isspace((text->text)[i]))
150         ++i;
151     return i;
152 };
153
154 int next_blank(cstring_t *text, int i) {
155     while ((i < text->size) && !isspace((text->text)[i]))
156         ++i;
157     return i;
158 };
159