]> ocean-lang.org Git - ocean/blob - csrc/boot-strap/libmdcode.c
a91bd60f2817efc55c2c1645ec636d4dc667d9ee
[ocean] / csrc / boot-strap / libmdcode.c
1 #line 101 "../mdcode.mdc"
2 #define _GNU_SOURCE
3 #include <unistd.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6
7 #include "mdcode.h"
8 #line 470 "../mdcode.mdc"
9 #include  <ctype.h>
10 #include  <string.h>
11
12 #line 187 "../mdcode.mdc"
13 struct psection {
14         struct section;
15         struct code_node *last;
16         int refcnt;
17         int indent;
18 };
19
20 #line 224 "../mdcode.mdc"
21 static void code_linearize(struct code_node *code)
22 {
23         struct code_node *t;
24         for (t = code; t; t = t->next)
25                 t->indent = 0;
26         for (; code; code = code->next)
27                 if (code->child) {
28                         struct code_node *next = code->next;
29                         struct psection *pchild =
30                                 (struct psection *)code->child;
31                         int indent = pchild->indent;
32                         code->next = code->child->code;
33                         code->child->code = NULL;
34                         code->child = NULL;
35                         for (t = code; t->next; t = t->next)
36                                 t->next->indent = code->indent + indent;
37                         t->next = next;
38                 }
39 }
40
41 #line 247 "../mdcode.mdc"
42 void code_free(struct code_node *code)
43 {
44         while (code) {
45                 struct code_node *this;
46                 if (code->child)
47                         code_linearize(code);
48                 this = code;
49                 code = code->next;
50                 free(this);
51         }
52 }
53
54 #line 276 "../mdcode.mdc"
55 static void code_add_text(struct psection *where, struct text txt,
56                           int line_no, int needs_strip)
57 {
58         struct code_node *n;
59         if (txt.len == 0)
60                 return;
61         n = malloc(sizeof(*n));
62         n->code = txt;
63         n->indent = 0;
64         n->line_no = line_no;
65         n->needs_strip = needs_strip;
66         n->next = NULL;
67         n->child = NULL;
68         if (where->last)
69                 where->last->next = n;
70         else
71                 where->code = n;
72         where->last = n;
73 }
74
75 #line 299 "../mdcode.mdc"
76 void code_add_link(struct psection *where, struct psection *to,
77                    int indent)
78 {
79         struct code_node *n;
80
81         to->indent = indent;
82         to->refcnt++;   // this will be checked elsewhere
83         if (where->last && where->last->child == NULL) {
84                 where->last->child = to;
85                 return;
86         }
87         n = malloc(sizeof(*n));
88         n->code.len = 0;
89         n->indent = 0;
90         n->line_no = 0;
91         n->next = NULL;
92         n->child = to;
93         if (where->last)
94                 where->last->next = n;
95         else
96                 where->code = n;
97         where->last = n;
98 }
99
100 #line 338 "../mdcode.mdc"
101 static int text_cmp(struct text a, struct text b)
102 {
103         if (a.len != b.len)
104                 return a.len - b.len;
105         return strncmp(a.txt, b.txt, a.len);
106 }
107
108 static struct psection *section_find(struct psection **list, struct text name)
109 {
110         struct psection *new;
111         while (*list) {
112                 int cmp = text_cmp((*list)->section, name);
113                 if (cmp == 0)
114                         return *list;
115                 if (cmp > 0)
116                         break;
117                 list = (struct psection **)&((*list)->next);
118         }
119         /* Add this section */
120         new = malloc(sizeof(*new));
121         new->next = *list;
122         *list = new;
123         new->section = name;
124         new->code = NULL;
125         new->last = NULL;
126         new->refcnt = 0;
127         new->indent = 0;
128         return new;
129 }
130
131 #line 419 "../mdcode.mdc"
132 static char *skip_lws(char *pos, char *end)
133 {
134         while (pos < end && (*pos == ' ' || *pos == '\t'))
135                 pos++;
136         return pos;
137 }
138
139 static char *skip_line(char *pos, char *end)
140 {
141         while (pos < end && *pos != '\n')
142                 pos++;
143         if (pos < end)
144                 pos++;
145         return pos;
146 }
147
148 static char *skip_para(char *pos, char *end, int *line_no)
149 {
150         /* Might return a pointer to a blank line, as only
151          * one trailing blank line is skipped
152          */
153         if (*pos == '#') {
154                 pos = skip_line(pos, end);
155                 (*line_no) += 1;
156                 return pos;
157         }
158         while (pos < end &&
159                *pos != '#' &&
160                *(pos = skip_lws(pos, end)) != '\n') {
161                 pos = skip_line(pos, end);
162                 (*line_no) += 1;
163         }
164         if (pos < end && *pos == '\n') {
165                 pos++;
166                 (*line_no) += 1;
167         }
168         return pos;
169 }
170
171 #line 475 "../mdcode.mdc"
172 static struct text take_header(char *pos, char *end)
173 {
174         struct text section;
175
176         while (pos < end && *pos == '#')
177                 pos++;
178         while (pos < end && *pos == ' ')
179                 pos++;
180         section.txt = pos;
181         while (pos < end && *pos != '\n')
182                 pos++;
183         while (pos > section.txt &&
184                (pos[-1] == '#' || pos[-1] == ' '))
185                 pos--;
186         section.len = pos - section.txt;
187         return section;
188 }
189
190 static int is_list(char *pos, char *end)
191 {
192         if (strchr("-*+", *pos))
193                 return 1;
194         if (isdigit(*pos)) {
195                 while (pos < end && isdigit(*pos))
196                         pos += 1;
197                 if  (pos < end && *pos == '.')
198                         return 1;
199         }
200         return 0;
201 }
202
203 static int matches(char *start, char *pos, char *end)
204 {
205         if (start == NULL)
206                 return matches("\t", pos, end) ||
207                        matches("    ", pos, end);
208         return (pos + strlen(start) < end &&
209                 strncmp(pos, start, strlen(start)) == 0);
210 }
211
212 #line 547 "../mdcode.mdc"
213 static int count_space(char *sol, char *p)
214 {
215         int c = 0;
216         while (sol < p) {
217                 if (sol[0] == ' ')
218                         c++;
219                 if (sol[0] == '\t')
220                         c+= 8;
221                 sol++;
222         }
223         return c;
224 }
225
226
227 static char *take_code(char *pos, char *end, char *marker,
228                        struct psection **table, struct text section,
229                        int *line_nop)
230 {
231         char *start = pos;
232         int line_no = *line_nop;
233         int start_line = line_no;
234         struct psection *sect;
235
236         sect = section_find(table, section);
237
238         while (pos < end) {
239                 char *sol, *t;
240                 struct text ref;
241
242                 if (marker && matches(marker, pos, end))
243                         break;
244                 if (!marker &&
245                     (skip_lws(pos, end))[0] != '\n' &&
246                     !matches(NULL, pos, end))
247                         /* Paragraph not indented */
248                         break;
249
250                 /* Still in code - check for reference */
251                 sol = pos;
252                 if (!marker) {
253                         if (*sol == '\t')
254                                 sol++;
255                         else if (strcmp(sol, "    ") == 0)
256                                 sol += 4;
257                 }
258                 t = skip_lws(sol, end);
259                 if (t[0] != '#' || t[1] != '#') {
260                         /* Just regular code here */
261                         pos = skip_line(sol, end);
262                         line_no++;
263                         continue;
264                 }
265
266                 if (pos > start) {
267                         struct text txt;
268                         txt.txt = start;
269                         txt.len = pos - start;
270                         code_add_text(sect, txt, start_line,
271                                       marker == NULL);
272                 }
273                 ref = take_header(t, end);
274                 if (ref.len) {
275                         struct psection *refsec = section_find(table, ref);
276                         code_add_link(sect, refsec, count_space(sol, t));
277                 }
278                 pos = skip_line(t, end);
279                 line_no++;
280                 start = pos;
281                 start_line = line_no;
282         }
283         if (pos > start) {
284                 struct text txt;
285                 txt.txt = start;
286                 txt.len = pos - start;
287                 code_add_text(sect, txt, start_line,
288                               marker == NULL);
289         }
290         if (marker) {
291                 pos = skip_line(pos, end);
292                 line_no++;
293         }
294         *line_nop = line_no;
295         return pos;
296 }
297
298 #line 641 "../mdcode.mdc"
299 static struct psection *code_find(char *pos, char *end)
300 {
301         struct psection *table = NULL;
302         int in_list = 0;
303         int line_no = 1;
304         struct text section = {0};
305
306         while (pos < end) {
307                 if (pos[0] == '#') {
308                         section = take_header(pos, end);
309                         in_list = 0;
310                         pos = skip_line(pos, end);
311                         line_no++;
312                 } else if (is_list(pos, end)) {
313                         in_list = 1;
314                         pos = skip_para(pos, end, &line_no);
315                 } else if (!in_list && matches(NULL, pos, end)) {
316                         pos = take_code(pos, end, NULL, &table,
317                                         section, &line_no);
318                 } else if (matches("```", pos, end)) {
319                         in_list = 0;
320                         pos = skip_line(pos, end);
321                         line_no++;
322                         pos = take_code(pos, end, "```", &table,
323                                         section, &line_no);
324                 } else if (matches("~~~", pos, end)) {
325                         in_list = 0;
326                         pos = skip_line(pos, end);
327                         line_no++;
328                         pos = take_code(pos, end, "~~~", &table,
329                                         section, &line_no);
330                 } else {
331                         if (!isspace(*pos))
332                                 in_list = 0;
333                         pos = skip_para(pos, end, &line_no);
334                 }
335         }
336         return table;
337 }
338
339 #line 701 "../mdcode.mdc"
340 struct section *code_extract(char *pos, char *end, code_err_fn error)
341 {
342         struct psection *table;
343         struct section *result = NULL;
344         struct section *tofree = NULL;
345
346         table = code_find(pos, end);
347
348         while (table) {
349                 struct psection *t = (struct psection*)table->next;
350                 if (table->last == NULL) {
351                         char *msg;
352                         asprintf(&msg,
353                                 "Section \"%.*s\" is referenced but not declared",
354                                  table->section.len, table->section.txt);
355                         error(msg);
356                         free(msg);
357                 }
358                 if (table->refcnt == 0) {
359                         /* Root-section,  return it */
360                         table->next = result;
361                         result = table;
362                         code_linearize(result->code);
363                 } else {
364                         table->next = tofree;
365                         tofree = table;
366                         if (table->refcnt > 1) {
367                                 char *msg;
368                                 asprintf(&msg,
369                                          "Section \"%.*s\" referenced multiple times (%d).",
370                                          table->section.len, table->section.txt,
371                                          table->refcnt);
372                                 error(msg);
373                                 free(msg);
374                         }
375                 }
376                 table = t;
377         }
378         while (tofree) {
379                 struct section *t = tofree->next;
380                 free(tofree);
381                 tofree = t;
382         }
383         return result;
384 }
385
386 #line 782 "../mdcode.mdc"
387 void code_node_print(FILE *out, struct code_node *node,
388                      char *fname)
389 {
390         for (; node; node = node->next) {
391                 char *c = node->code.txt;
392                 int len = node->code.len;
393
394                 if (!len)
395                         continue;
396
397                 fprintf(out, "#line %d \"%s\"\n",
398                         node->line_no, fname);
399                 while (len && *c) {
400                         fprintf(out, "%*s", node->indent, "");
401                         if (node->needs_strip) {
402                                 if (*c == '\t' && len > 1) {
403                                         c++;
404                                         len--;
405                                 } else if (strncmp(c, "    ", 4) == 0 && len > 4) {
406                                         c += 4;
407                                         len-= 4;
408                                 }
409                         }
410                         do {
411                                 fputc(*c, out);
412                                 c++;
413                                 len--;
414                         } while (len && c[-1] != '\n');
415                 }
416         }
417 }
418
419 #line 110 "../mdcode.mdc"
420