rename objects to deck / slide
[smdp.git] / parser.c
1 #include <stdio.h>
2 #include <stdlib.h>
3
4 #include "include/parser.h"
5
6 deck_t *markdown_load(FILE *input) {
7
8     int c = 0, i = 0, l = 0, bits = 0;
9
10     deck_t *deck;
11     slide_t *slide;
12     line_t *line;
13     cstring_t *text;
14
15     deck = new_deck();
16     slide = new_slide();
17     deck->slide = slide;
18     text = cstring_init();
19
20     while ((c = fgetc(input)) != EOF) {
21         if(c == '\n') {
22
23             // markdown analyse
24             bits = markdown_analyse(text);
25
26             // if text is markdown hr
27             if(CHECK_BIT(bits, IS_HR) &&
28                CHECK_BIT(line->bits, IS_EMPTY)) {
29
30                 // clear text
31                 (text->reset)(text);
32
33                 // reset line length
34                 l = 0;
35
36                 // create next slide
37                 slide = next_slide(slide);
38
39             } else {
40
41                 // if slide ! has line
42                 if(!slide->line) {
43
44                     // create new line
45                     line = new_line();
46                     slide->line = line;
47
48                 } else {
49
50                     // create next line
51                     line = next_line(line);
52
53                 }
54
55                 // add text to line
56                 line->text = text;
57
58                 // add bits to line
59                 line->bits = bits;
60
61                 // add length to line
62                 line->length = l;
63
64                 // calc offset
65                 line->offset = next_nonblank(text, 0);
66
67                 // new text
68                 text = cstring_init();
69
70                 // reset line length
71                 l = 0;
72             }
73
74         } else if(c == '\t') {
75
76             // expand tab to spaces
77             for (i = 0;  i <= 4;  i++) {
78                 (text->expand)(text, ' ');
79                 l++;
80             }
81
82         } else if(isprint(c) || isspace(c)) {
83
84             // add char to line
85             (text->expand)(text, c);
86
87             // increase line lenght
88             l++;
89
90         } else if(is_utf8(c)) {
91
92             // add char to line
93             (text->expand)(text, c);
94
95             // if utf-8 char > 1 byte add remaing to line
96             for(i = 0; i < length_utf8(c) - 1; i++) {
97                 c = fgetc(input);
98                 (text->expand)(text, c);
99             }
100
101             // increase line length
102             l++;
103         }
104     }
105
106     // detect header
107     line = deck->slide->line;
108     if(line && line->text->size > 0 && line->text->text[0] == '%') {
109
110         // assign header to deck
111         deck->header = line;
112
113         // find first non-header line
114         while(line->text->size > 0 && line->text->text[0] == '%') {
115             line = line->next;
116         }
117
118         // split linked list
119         line->prev->next = (void*)0;
120         line->prev = (void*)0;
121
122         // remove header lines from slide
123         deck->slide->line = line;
124     }
125
126     // combine underlined H1/H2 in single line
127     slide = deck->slide;
128     while(slide) {
129         line = slide->line;
130         while(line) {
131             if((CHECK_BIT(line->bits, IS_H1) ||
132                 CHECK_BIT(line->bits, IS_H2)) &&
133                CHECK_BIT(line->bits, IS_EMPTY) &&
134                line->prev &&
135                !CHECK_BIT(line->prev->bits, IS_EMPTY)) {
136
137                 // remove line from linked list
138                 line->prev->next = line->next;
139                 line->next->prev = line->prev;
140
141                 // set bits on revious line
142                 if(CHECK_BIT(line->bits, IS_H1)) {
143                     SET_BIT(line->prev->bits, IS_H1);
144                 } else {
145                     SET_BIT(line->prev->bits, IS_H2);
146                 }
147
148                 // delete line
149                 (line->text->delete)(line->text);
150                 free(line);
151             }
152             line = line->next;
153         }
154         slide = slide->next;
155     }
156
157     return deck;
158 }
159
160 int markdown_analyse(cstring_t *text) {
161     int i = 0, bits = 0,
162         offset = 0, eol    = 0,
163         equals = 0, hashes = 0,
164         stars  = 0, minus  = 0,
165         spaces = 0, other  = 0;
166
167     // count leading spaces
168     offset = next_nonblank(text, 0);
169
170     // strip trailing spaces
171     for(eol = text->size; eol > offset && isspace(text->text[eol - 1]); eol--);
172
173     for(i = offset; i < eol; i++) {
174
175         switch(text->text[i]) {
176             case '=': equals++;  break;
177             case '#': hashes++;  break;
178             case '*': stars++;   break;
179             case '-': minus++;   break;
180             case ' ': spaces++;  break;
181             default:  other++;   break;
182         }
183     }
184
185     // IS_H1
186     if((equals > 0 &&
187         hashes + stars + minus + spaces + other == 0) ||
188        (text &&
189         text->text &&
190         text->text[offset] == '#' &&
191         text->text[offset+1] != '#')) {
192
193         SET_BIT(bits, IS_H1);
194     }
195
196     // IS_H2
197     if((minus > 0 &&
198         equals + hashes + stars + spaces + other == 0) ||
199        (text &&
200         text->text &&
201         text->text[offset] == '#' &&
202         text->text[offset+1] == '#')) {
203
204         SET_BIT(bits, IS_H2);
205     }
206
207     // IS_QUOTE
208     if(text &&
209        text->text &&
210        text->text[offset] == '>') {
211
212         SET_BIT(bits, IS_QUOTE);
213     }
214
215     // IS_CODE
216     if(offset >= 4) {
217         SET_BIT(bits, IS_CODE);
218     }
219
220     // IS_HR
221     if((minus >= 3 && equals + hashes + stars + other == 0) ||
222        (stars >= 3 && equals + hashes + minus + other == 0)) {
223
224         SET_BIT(bits, IS_HR);
225     }
226
227     // IS_EMPTY
228     if(other == 0) {
229         SET_BIT(bits, IS_EMPTY);
230     }
231
232     return bits;
233 }
234
235 void markdown_debug(deck_t *deck, int debug) {
236
237     // print header to STDERR
238     int offset;
239     line_t *header;
240     if(deck->header) {
241         header = deck->header;
242         while(header &&
243             header->length > 0 &&
244             header->text->text[0] == '%') {
245
246             offset = next_blank(header->text, 0) + 1;
247             fprintf(stderr, "header: %s\n", &header->text->text[offset]);
248             header = header->next;
249         }
250     }
251
252     // print slide/line count to STDERR
253     int cs = 0, cl = 0;
254     slide_t *slide = deck->slide;
255     line_t *line;
256     while(slide) {
257         cs++;
258         if(debug > 1) {
259             fprintf(stderr, "slide %i:\n", cs);
260         }
261         line = slide->line;
262         cl = 0;
263         while(line) {
264             cl++;
265             if(debug > 1) {
266                 fprintf(stderr, "  line %i: bits = %i, length = %i\n", cl, line->bits, line->length);
267             }
268             line = line->next;
269         }
270         if(debug == 1) {
271             fprintf(stderr, "slide %i: %i lines\n", cs, cl);
272         }
273         slide = slide->next;
274     }
275 }
276
277
278 int is_utf8(char ch) {
279     return (ch & 0x80);
280 }
281
282 int length_utf8(char ch) {
283     int i = 0;
284     while(ch & 0x80) {
285         i++;
286         ch <<= 1;
287     }
288     return i;
289 }
290
291 int next_nonblank(cstring_t *text, int i) {
292     while ((i < text->size) && isspace((text->text)[i]))
293         ++i;
294     return i;
295 };
296
297 int next_blank(cstring_t *text, int i) {
298     while ((i < text->size) && !isspace((text->text)[i]))
299         ++i;
300     return i;
301 };
302