]> ocean-lang.org Git - ocean/blob - csrc/mdcode.mdc
ac34a54c027fb353ea42ffcb4feb4608d144d57c
[ocean] / csrc / mdcode.mdc
1 # mdcode: extract C code from a _markdown_ file.
2
3 _markdown_ is a popular format for simple text markup which can easily
4 be converted to HTML.  As it allows easy indication of sections of
5 code, it is quite suitable for use in literate programming.  This file
6 is an example of that usage.
7
8 The code included below provides two related functionalities.
9 Firstly it provides a library routine for extracting code out of a
10 _markdown_ file, so that other routines might make use of it.
11
12 Secondly it provides a simple client of this routine which extracts
13 1 or more C-language files from a markdown document so they can be
14 passed to a C compiler.  These two combined to make a tool that is needed
15 to compile this tool.  Yes, this is circular.  A prototype tool was
16 used for the first extraction.
17
18 The tool provided is described as specific to the C language as it
19 generates
20
21 ##### Example: a _line_ command
22
23         #line __line-number__ __file-name__
24
25 lines so that the C compiler will report where in the markdown file
26 any error is found.  This tool is suitable for any other language
27 which allows the same directive, or will treat it as a comment.
28
29 ## Literate Details
30
31 Literate programming is more than just including comments with the
32 code, even nicely formatted comments.  It also involves presenting the
33 code in an order that makes sense to a human, rather than an order
34 that makes sense to a compiler.  For this reason a core part of any
35 literate programming tool is the ability to re-arrange the code found
36 in the document into a different order in the final code file - or
37 files.  This requires some form of linkage to be encoded.
38
39 The approach taken here is focused around section headings - of any
40 depth.
41
42 All the code in any section is treated as a single sequential
43 collection of code, and is named by the section that it is in.  If
44 multiple sections have the same name, then the code blocks in all of
45 them are joined together in the order they appear in the document.
46
47 A code section can contain a special marker which starts with 2
48 hashes: __##__.
49 The text after the marker must be the name of some section which
50 contains code.  Code from that section will be interpolated in place
51 of the marker, and will be indented to match the indent of the marker.
52
53 It is not permitted for the same code to be interpolated multiple
54 times.  Allowing this might make some sense, but it is probably a
55 mistake, and prohibiting it make some of the code a bit cleaner.
56
57 Equally, every section of code should be interpolated at least once -
58 with one exception.  This exception is imposed by the
59 tool, not the library.  A different client could impose different
60 rules on the names of top-level code sections.
61
62 One example of the exception we have already seen.  A section name
63 starting __Example:__ indicates code that is not to be included in the
64 final product.  Any leading word will do, providing there is a space,
65 and the first space is preceded by a colon, that section name will be
66 ignored.
67
68 A special case of this exception exists for the leading word
69 __File__.  These sections are the top level code sections and they
70 will be written to the named file.  Thus a section named
71 __File: foo__ should not be referenced by another section, and its
72 contents after all references are expanded will be written to the file
73 __foo__.
74
75 Any section containing code that does not start __Word:__
76 must be included in some other section exactly once.
77
78 ### Multiple files
79
80 Allowing multiple top level code sections which name different files
81 means that one _markdown_ document can describe several files.  This
82 is very useful with the C language where a program file and a header
83 file might be related.  For the present document we will have a header
84 file and two code files, one with the library content and one for the
85 tool.
86
87 It will also be very convenient to create a `makefile` fragment to
88 ensure the code is compiled correctly.  A simple `make -f mdcode.mk`
89 will "do the right thing".
90
91 ### File: mdcode.mk
92
93         CFLAGS += -Wall -g
94         all::
95         mdcode.h libmdcode.c md2c.c mdcode.mk :  mdcode.mdc
96                 ./md2c mdcode.mdc
97
98
99 ### File: mdcode.h
100
101         #include <stdio.h>
102         ## exported types
103         ## exported functions
104
105 ### File: libmdcode.c
106         #define _GNU_SOURCE
107         #include <unistd.h>
108         #include <stdlib.h>
109         #include <stdio.h>
110
111         #include "mdcode.h"
112         ## internal includes
113         ## private types
114         ## internal functions
115
116 ### File: mdcode.mk
117
118         all :: libmdcode.o
119         libmdcode.o : libmdcode.c mdcode.h
120                 $(CC) $(CFLAGS) -c libmdcode.c
121
122
123 ### File: md2c.c
124
125         #include <unistd.h>
126         #include <stdlib.h>
127         #include <stdio.h>
128
129         #include "mdcode.h"
130
131         ## client includes
132         ## client functions
133
134 ### File: mdcode.mk
135
136         all :: md2c
137         md2c : md2c.o libmdcode.o
138                 $(CC) $(CFLAGS) -o md2c md2c.o libmdcode.o
139         md2c.o : md2c.c mdcode.h
140                 $(CC) $(CFLAGS) -c md2c.c
141
142 ## Data Structures
143
144 As the core purpose of _mdcode_ is to discover and re-arrange blocks
145 of text, it makes sense to map the whole document file into memory and
146 produce a data structure which lists various parts of the file in the
147 appropriate order.  Each node in this structure will have some text
148 from the document, a child pointer, and a next pointer, any of which
149 might not be present.  The text is most easily stored as a pointer and a
150 length.  We'll call this a `text`
151
152 A list of these `code_nodes` will belong to each section and it will
153 be useful to have a separate `section` data structure to store the
154 list of `code_nodes`, the section name, and some other information.
155
156 This other information will include a reference counter so we can
157 ensure proper referencing, and an `indent` depth.  As referenced
158 content can have an extra indent added, we need to know what that is.
159 The `code_node` will also have an `indent` depth which eventually gets
160 set to the sum for the indents from all references on the path from
161 the root.
162
163 Finally we need to know if the `code_node` was recognised by being
164 indented or not.  If it was, the client of this data will want to
165 strip of the leading tab or 4 spaces.  Hence a `needs_strip` flag is
166 needed.
167
168 ##### exported types
169
170         struct text {
171                 char *txt;
172                 int len;
173         };
174
175         struct section {
176                 struct text section;
177                 struct code_node *code;
178                 struct section *next;
179         };
180
181         struct code_node {
182                 struct text code;
183                 int indent;
184                 int line_no;
185                 int needs_strip;
186                 struct code_node *next;
187                 struct section *child;
188         };
189
190 ##### private types
191
192         struct psection {
193                 struct section;
194                 struct code_node *last;
195                 int refcnt;
196                 int indent;
197         };
198
199 You will note that the `struct psection` contains an anonymous `struct
200 section` embedded at the start.  To make this work right, GCC
201 requires the `-fplan9-extensions` flag.
202
203 ##### File: mdcode.mk
204
205         CFLAGS += -fplan9-extensions
206
207 ### Manipulating the node
208
209 Though a tree with `next` and `child` links is the easiest way to
210 assemble the various code sections, it is not the easiest form for
211 using them.  For that a simple list would be best.
212
213 So once we have a fully linked File section we will want to linearize
214 it, so that the `child` links become `NULL` and the `next` links will
215 find everything required.  It is at this stage that the requirements
216 that each section is linked only once becomes import.
217
218 `code_linearize` will merge the `code_node`s from any child into the
219 given `code_node`.  As it does this it sets the 'indent' field for
220 each `code_node`.
221
222 Note that we don't clear the section's `last` pointer, even though
223 it no longer owns any code.  This allows subsequent code to see if a
224 section ever had any code, and to report an error if a section is
225 referenced but not defined.
226
227 ##### internal functions
228
229         static void code_linearize(struct code_node *code)
230         {
231                 struct code_node *t;
232                 for (t = code; t; t = t->next)
233                         t->indent = 0;
234                 for (; code; code = code->next)
235                         if (code->child) {
236                                 struct code_node *next = code->next;
237                                 struct psection *pchild =
238                                         (struct psection *)code->child;
239                                 int indent = pchild->indent;
240                                 code->next = code->child->code;
241                                 code->child->code = NULL;
242                                 code->child = NULL;
243                                 for (t = code; t->next; t = t->next)
244                                         t->next->indent = code->indent + indent;
245                                 t->next = next;
246                         }
247         }
248
249 Once a client has made use of a linearized code set, it will probably
250 want to free it.
251
252         void code_free(struct code_node *code)
253         {
254                 while (code) {
255                         struct code_node *this;
256                         if (code->child)
257                                 code_linearize(code);
258                         this = code;
259                         code = code->next;
260                         free(this);
261                 }
262         }
263
264 ##### exported functions
265
266         void code_free(struct code_node *code);
267
268 ### Building the tree
269
270 As we parse the document there are two things we will want to do to
271 node trees: add some text or add a reference.  We'll assume for now
272 that the relevant section structures have been found, and will just
273 deal with the `code_node`.
274
275 Adding text simply means adding another node.  We will never have
276 empty nodes, even if the last node only has a child, new text must go
277 in a new node.
278
279 ##### internal functions
280
281         static void code_add_text(struct psection *where, struct text txt,
282                                   int line_no, int needs_strip)
283         {
284                 struct code_node *n;
285                 if (txt.len == 0)
286                         return;
287                 n = malloc(sizeof(*n));
288                 n->code = txt;
289                 n->indent = 0;
290                 n->line_no = line_no;
291                 n->needs_strip = needs_strip;
292                 n->next = NULL;
293                 n->child = NULL;
294                 if (where->last)
295                         where->last->next = n;
296                 else
297                         where->code = n;
298                 where->last = n;
299         }
300
301 However when adding a link, we might be able to include it in the last
302 `code_node` if it currently only has text.
303
304         void code_add_link(struct psection *where, struct psection *to,
305                            int indent)
306         {
307                 struct code_node *n;
308
309                 to->indent = indent;
310                 to->refcnt++;   // this will be checked elsewhere
311                 if (where->last && where->last->child == NULL) {
312                         where->last->child = to;
313                         return;
314                 }
315                 n = malloc(sizeof(*n));
316                 n->code.len = 0;
317                 n->indent = 0;
318                 n->line_no = 0;
319                 n->next = NULL;
320                 n->child = to;
321                 if (where->last)
322                         where->last->next = n;
323                 else
324                         where->code = n;
325                 where->last = n;
326         }
327
328 ### Finding sections
329
330 Now we need a lookup table to be able to find sections by name.
331 Something that provides an `n*log(N)` search time is probably
332 justified, but for now I want a minimal stand-alone program so a
333 linked list managed by insertion-sort will do.  As a comparison
334 function it is easiest to sort based on length before content.  So
335 sections won't be in standard lexical order, but that isn't important.
336
337 If we cannot find a section, we simply want to create it.  This allows
338 sections and references to be created in any order.  Sections with
339 no references or no content will cause a warning eventually.
340
341 #### internal functions
342
343         static int text_cmp(struct text a, struct text b)
344         {
345                 if (a.len != b.len)
346                         return a.len - b.len;
347                 return strncmp(a.txt, b.txt, a.len);
348         }
349
350         static struct psection *section_find(struct psection **list, struct text name)
351         {
352                 struct psection *new;
353                 while (*list) {
354                         int cmp = text_cmp((*list)->section, name);
355                         if (cmp == 0)
356                                 return *list;
357                         if (cmp > 0)
358                                 break;
359                         list = (struct psection **)&((*list)->next);
360                 }
361                 /* Add this section */
362                 new = malloc(sizeof(*new));
363                 new->next = *list;
364                 *list = new;
365                 new->section = name;
366                 new->code = NULL;
367                 new->last = NULL;
368                 new->refcnt = 0;
369                 new->indent = 0;
370                 return new;
371         }
372
373 ## Parsing the _markdown_
374
375 Parsing markdown is fairly easy, though there are complications.
376
377 The document is divided into "paragraphs" which are mostly separated by blank
378 lines (which may contain white space).  The first few characters of
379 the first line of a paragraph determine the type of paragraph.  For
380 our purposes we are only interested in list paragraphs, code
381 paragraphs, section headings, and everything else.  Section headings
382 are single-line paragraphs and so do not require a preceding or
383 following blank line.
384
385 Section headings start with 1 or more hash characters (__#__).  List
386 paragraphs start with hyphen, asterisk, plus, or digits followed by a
387 period.  Code paragraphs aren't quite so easy.
388
389 The "standard" code paragraph starts with 4 or more spaces, or a tab.
390 However if the previous paragraph was a list paragraph, then those
391 spaces indicate another  paragraph in the same list item, and 8 or
392 more spaces are required.  Unless a nested list is in effect, in
393 which case 12 or more are need.   Unfortunately not all _markdown_
394 parsers agree on nested lists.
395
396 Two alternate styles for marking code are in active use.  "Github" uses
397 three backticks(_`` ``` ``_), while "pandoc" uses three or more tildes
398 (_~~~_).  In these cases the code should not be indented.
399
400 Trying to please everyone as much as possible, this parser will handle
401 everything except for code inside lists.
402
403 So an indented (4+) paragraph after a list paragraph is always a list
404 paragraph, otherwise it is a code paragraph.  A paragraph that starts
405 with three backticks or three tildes is code which continues until a
406 matching string of backticks or tildes.
407
408 ### Skipping bits
409
410 While walking the document looking for various markers we will *not*
411 use the `struct text` introduced earlier as advancing that requires
412 updating both start and length which feels clumsy.  Instead we will
413 carry `pos` and `end` pointers, only the first of which needs to
414 change.
415
416 So to start, we need to skip various parts of the document.  `lws`
417 stands for "Linear White Space" and is a term that comes from the
418 Email RFCs (e.g. RFC822).  `line` and `para` are self explanatory.
419 Note that `skip_para` needs to update the current line number.
420 `skip_line` doesn't but every caller should.
421
422 #### internal functions
423
424         static char *skip_lws(char *pos, char *end)
425         {
426                 while (pos < end && (*pos == ' ' || *pos == '\t'))
427                         pos++;
428                 return pos;
429         }
430
431         static char *skip_line(char *pos, char *end)
432         {
433                 while (pos < end && *pos != '\n')
434                         pos++;
435                 if (pos < end)
436                         pos++;
437                 return pos;
438         }
439
440         static char *skip_para(char *pos, char *end, int *line_no)
441         {
442                 /* Might return a pointer to a blank line, as only
443                  * one trailing blank line is skipped
444                  */
445                 if (*pos == '#') {
446                         pos = skip_line(pos, end);
447                         (*line_no) += 1;
448                         return pos;
449                 }
450                 while (pos < end &&
451                        *pos != '#' &&
452                        *(pos = skip_lws(pos, end)) != '\n') {
453                         pos = skip_line(pos, end);
454                         (*line_no) += 1;
455                 }
456                 if (pos < end && *pos == '\n') {
457                         pos++;
458                         (*line_no) += 1;
459                 }
460                 return pos;
461         }
462
463 ### Recognising things
464
465 Recognising a section header is trivial and doesn't require a
466 function.  However we need to extract the content of a section header
467 as a `struct text` for passing to `section_find`.
468 Recognising the start of a new list is fairly easy.  Recognising the
469 start (and end) of code is a little messy so we provide a function for
470 matching the first few characters, which has a special case for "4
471 spaces or tab".
472
473 #### internal includes
474
475         #include  <ctype.h>
476         #include  <string.h>
477
478 #### internal functions
479
480         static struct text take_header(char *pos, char *end)
481         {
482                 struct text section;
483
484                 while (pos < end && *pos == '#')
485                         pos++;
486                 while (pos < end && *pos == ' ')
487                         pos++;
488                 section.txt = pos;
489                 while (pos < end && *pos != '\n')
490                         pos++;
491                 while (pos > section.txt &&
492                        (pos[-1] == '#' || pos[-1] == ' '))
493                         pos--;
494                 section.len = pos - section.txt;
495                 return section;
496         }
497
498         static int is_list(char *pos, char *end)
499         {
500                 if (strchr("-*+", *pos))
501                         return 1;
502                 if (isdigit(*pos)) {
503                         while (pos < end && isdigit(*pos))
504                                 pos += 1;
505                         if  (pos < end && *pos == '.')
506                                 return 1;
507                 }
508                 return 0;
509         }
510
511         static int matches(char *start, char *pos, char *end)
512         {
513                 if (start == NULL)
514                         return matches("\t", pos, end) ||
515                                matches("    ", pos, end);
516                 return (pos + strlen(start) < end &&
517                         strncmp(pos, start, strlen(start)) == 0);
518         }
519
520 ### Extracting the code
521
522 Now that we can skip paragraphs and recognise what type each paragraph
523 is, it is time to parse the file and extract the code.  We'll do this
524 in two parts, first we look at what to do with some code once we
525 find it, and then how to actually find it.
526
527 When we have some code, we know where it is, what the end marker
528 should look like, and which section it is in.
529
530 There are two sorts of end markers: the presence of a particular
531 string, or the absence of an indent.  We will use a string to
532 represent a presence, and a `NULL` to represent the absence.
533
534 While looking at code we don't think about paragraphs are all - just
535 look for a line that starts with the right thing.
536 Every line that is still code then needs to be examined to see if it
537 is a section reference.
538
539 When a section reference is found, all preceding code (if any) must be
540 added to the current section, then the reference is added.
541
542 When we do find the end of the code, all text that we have found but
543 not processed needs to be saved too.
544
545 When adding a reference we need to set the `indent`.  This is the
546 number of spaces (counting 8 for tabs) after the natural indent of the
547 code (which is a tab or 4 spaces).  We use a separate function `count_spaces`
548 for that.
549
550 #### internal functions
551
552         static int count_space(char *sol, char *p)
553         {
554                 int c = 0;
555                 while (sol < p) {
556                         if (sol[0] == ' ')
557                                 c++;
558                         if (sol[0] == '\t')
559                                 c+= 8;
560                         sol++;
561                 }
562                 return c;
563         }
564
565
566         static char *take_code(char *pos, char *end, char *marker,
567                                struct psection **table, struct text section,
568                                int *line_nop)
569         {
570                 char *start = pos;
571                 int line_no = *line_nop;
572                 int start_line = line_no;
573                 struct psection *sect;
574
575                 sect = section_find(table, section);
576
577                 while (pos < end) {
578                         char *sol, *t;
579                         struct text ref;
580
581                         if (marker && matches(marker, pos, end))
582                                 break;
583                         if (!marker &&
584                             (skip_lws(pos, end))[0] != '\n' &&
585                             !matches(NULL, pos, end))
586                                 /* Paragraph not indented */
587                                 break;
588
589                         /* Still in code - check for reference */
590                         sol = pos;
591                         if (!marker) {
592                                 if (*sol == '\t')
593                                         sol++;
594                                 else if (strcmp(sol, "    ") == 0)
595                                         sol += 4;
596                         }
597                         t = skip_lws(sol, end);
598                         if (t[0] != '#' || t[1] != '#') {
599                                 /* Just regular code here */
600                                 pos = skip_line(sol, end);
601                                 line_no++;
602                                 continue;
603                         }
604
605                         if (pos > start) {
606                                 struct text txt;
607                                 txt.txt = start;
608                                 txt.len = pos - start;
609                                 code_add_text(sect, txt, start_line,
610                                               marker == NULL);
611                         }
612                         ref = take_header(t, end);
613                         if (ref.len) {
614                                 struct psection *refsec = section_find(table, ref);
615                                 code_add_link(sect, refsec, count_space(sol, t));
616                         }
617                         pos = skip_line(t, end);
618                         line_no++;
619                         start = pos;
620                         start_line = line_no;
621                 }
622                 if (pos > start) {
623                         struct text txt;
624                         txt.txt = start;
625                         txt.len = pos - start;
626                         code_add_text(sect, txt, start_line,
627                                       marker == NULL);
628                 }
629                 if (marker) {
630                         pos = skip_line(pos, end);
631                         line_no++;
632                 }
633                 *line_nop = line_no;
634                 return pos;
635         }
636
637 ### Finding the code
638
639 It is when looking for the code that we actually use the paragraph
640 structure.  We need to recognise section headings so we can record the
641 name, list paragraphs so we can ignore indented follow-on paragraphs,
642 and the three different markings for code.
643
644 #### internal functions
645
646         static struct psection *code_find(char *pos, char *end)
647         {
648                 struct psection *table = NULL;
649                 int in_list = 0;
650                 int line_no = 1;
651                 struct text section = {0};
652
653                 while (pos < end) {
654                         if (pos[0] == '#') {
655                                 section = take_header(pos, end);
656                                 in_list = 0;
657                                 pos = skip_line(pos, end);
658                                 line_no++;
659                         } else if (is_list(pos, end)) {
660                                 in_list = 1;
661                                 pos = skip_para(pos, end, &line_no);
662                         } else if (!in_list && matches(NULL, pos, end)) {
663                                 pos = take_code(pos, end, NULL, &table,
664                                                 section, &line_no);
665                         } else if (matches("```", pos, end)) {
666                                 in_list = 0;
667                                 pos = skip_line(pos, end);
668                                 line_no++;
669                                 pos = take_code(pos, end, "```", &table,
670                                                 section, &line_no);
671                         } else if (matches("~~~", pos, end)) {
672                                 in_list = 0;
673                                 pos = skip_line(pos, end);
674                                 line_no++;
675                                 pos = take_code(pos, end, "~~~", &table,
676                                                 section, &line_no);
677                         } else {
678                                 if (!isspace(*pos))
679                                         in_list = 0;
680                                 pos = skip_para(pos, end, &line_no);
681                         }
682                 }
683                 return table;
684         }
685
686 ### Returning the code
687
688 Having found all the code blocks and gathered them into a list of
689 section, we are now ready to return them to the caller.  This is where
690 to perform consistency checks, like at most one reference and at least
691 one definition for each section.
692
693 All the sections with no references are returned in a list for the
694 caller to consider.  The are linearized first so that the substructure
695 is completely hidden -- except for the small amount of structure
696 displayed in the line numbers.
697
698 To return errors, we have the caller pass a function which takes an
699 error message - a `code_err_fn`.
700
701 #### exported types
702
703         typedef void (*code_err_fn)(char *msg);
704
705 #### internal functions
706         struct section *code_extract(char *pos, char *end, code_err_fn error)
707         {
708                 struct psection *table;
709                 struct section *result = NULL;
710                 struct section *tofree = NULL;
711
712                 table = code_find(pos, end);
713
714                 while (table) {
715                         struct psection *t = (struct psection*)table->next;
716                         if (table->last == NULL) {
717                                 char *msg;
718                                 asprintf(&msg,
719                                         "Section \"%.*s\" is referenced but not declared",
720                                          table->section.len, table->section.txt);
721                                 error(msg);
722                                 free(msg);
723                         }
724                         if (table->refcnt == 0) {
725                                 /* Root-section,  return it */
726                                 table->next = result;
727                                 result = table;
728                                 code_linearize(result->code);
729                         } else {
730                                 table->next = tofree;
731                                 tofree = table;
732                                 if (table->refcnt > 1) {
733                                         char *msg;
734                                         asprintf(&msg,
735                                                  "Section \"%.*s\" referenced multiple times (%d).",
736                                                  table->section.len, table->section.txt,
737                                                  table->refcnt);
738                                         error(msg);
739                                         free(msg);
740                                 }
741                         }
742                         table = t;
743                 }
744                 while (tofree) {
745                         struct section *t = tofree->next;
746                         free(tofree);
747                         tofree = t;
748                 }
749                 return result;
750         }
751
752 ##### exported functions
753
754         struct section *code_extract(char *pos, char *end, code_err_fn error);
755
756
757 ## Using the library
758
759 Now that we can extract code from a document and link it all together
760 it is time to do something with that code.  Firstly we need to print
761 it out.
762
763 ### Printing the Code
764
765 Printing is mostly straight forward - we just walk the list and print
766 the code sections, adding whatever indent is required for each line.
767 However there is a complication (isn't there always)?
768
769 For code that was recognised because the paragraph was indented, we
770 need to strip that indent first.  For other code, we don't.
771
772 The approach taken here is simple, though it could arguably be wrong
773 in some unlikely cases.  So it might need to be fixed later.
774
775 If the first line of a code block is indented, then either one tab or
776 4 spaces are striped from every non-blank line.
777
778 This could go wrong if the first line of a code block marked by
779 _`` ``` ``_ is indented.  To overcome this we would need to
780 record some extra state in each `code_node`.  For now we won't bother.
781
782 The indents we insert will all be spaces.  This might not work well
783 for `Makefiles`.
784
785 ##### internal functions
786
787         void code_node_print(FILE *out, struct code_node *node,
788                              char *fname)
789         {
790                 for (; node; node = node->next) {
791                         char *c = node->code.txt;
792                         int len = node->code.len;
793
794                         if (!len)
795                                 continue;
796
797                         fprintf(out, "#line %d \"%s\"\n",
798                                 node->line_no, fname);
799                         while (len && *c) {
800                                 fprintf(out, "%*s", node->indent, "");
801                                 if (node->needs_strip) {
802                                         if (*c == '\t' && len > 1) {
803                                                 c++;
804                                                 len--;
805                                         } else if (strncmp(c, "    ", 4) == 0 && len > 4) {
806                                                 c += 4;
807                                                 len-= 4;
808                                         }
809                                 }
810                                 do {
811                                         fputc(*c, out);
812                                         c++;
813                                         len--;
814                                 } while (len && c[-1] != '\n');
815                         }
816                 }
817         }
818
819 ###### exported functions
820         void code_node_print(FILE *out, struct code_node *node, char *fname);
821
822 ### Bringing it all together
823
824 We are just about ready for the `main` function of the tool which will
825 extract all this lovely code and compile it.  Just one helper is still
826 needed.
827
828 #### Handling filenames
829
830 Section names are stored in `struct text` which is not `nul`
831 terminated.  Filenames passed to `open` need to be null terminated.
832 So we need to convert one to the other, and strip the leading `File:`
833 of while we are at it.
834
835 ##### client functions
836
837         static void copy_fname(char *name, int space, struct text t)
838         {
839                 char *sec = t.txt;
840                 int len = t.len;
841                 name[0] = 0;
842                 if (len < 5 || strncmp(sec, "File:", 5) != 0)
843                         return;
844                 sec += 5;
845                 len -= 5;
846                 while (len && sec[0] == ' ') {
847                         sec++;
848                         len--;
849                 }
850                 if (len >= space)
851                         len = space - 1;
852                 strncpy(name, sec, len);
853                 name[len] = 0;
854         }
855
856 #### Main
857
858 And now we take a single file name, extract the code, and if there are
859 no error we write out a file for each appropriate code section.  And
860 we are done.
861
862
863 ##### client includes
864
865         #include <fcntl.h>
866         #include <errno.h>
867         #include <sys/mman.h>
868         #include <string.h>
869
870 ##### client functions
871
872         static int errs;
873         static void pr_err(char *msg)
874         {
875                 errs++;
876                 fprintf(stderr, "%s\n", msg);
877         }
878
879         static char *strnchr(char *haystack, int len, char needle)
880         {
881                 while (len > 0 && *haystack && *haystack != needle) {
882                         haystack++;
883                         len--;
884                 }
885                 return len > 0 && *haystack == needle ? haystack : NULL;
886         }
887
888         int main(int argc, char *argv[])
889         {
890                 int fd;
891                 size_t len;
892                 char *file;
893                 struct section *table, *s, *prev;
894
895                 errs = 0;
896                 if (argc != 2) {
897                         fprintf(stderr, "Usage: mdcode file.mdc\n");
898                         exit(2);
899                 }
900                 fd = open(argv[1], O_RDONLY);
901                 if (fd < 0) {
902                         fprintf(stderr, "mdcode: cannot open %s: %s\n",
903                                 argv[1], strerror(errno));
904                         exit(1);
905                 }
906                 len = lseek(fd, 0, 2);
907                 file = mmap(NULL, len, PROT_READ, MAP_SHARED, fd, 0);
908                 table = code_extract(file, file+len, pr_err);
909
910                 for (s = table; s;
911                         (code_free(s->code), prev = s, s = s->next, free(prev))) {
912                         FILE *fl;
913                         char fname[1024];
914                         char *spc = strnchr(s->section.txt, s->section.len, ' ');
915
916                         if (spc > s->section.txt && spc[-1] == ':' &&
917                             strncmp(s->section.txt, "File: ", 6) != 0)
918                                 /* Ignore this section */
919                                 continue;
920                         if (strncmp(s->section.txt, "File: ", 6) != 0) {
921                                 fprintf(stderr, "Code in unreferenced section that is not ignored or a file name: %.*s\n",
922                                         s->section.len, s->section.txt);
923                                 errs++;
924                                 continue;
925                         }
926                         copy_fname(fname, sizeof(fname), s->section);
927                         if (fname[0] == 0) {
928                                 fprintf(stderr, "Missing file name at:%.*s\n",
929                                         s->section.len, s->section.txt);
930                                 errs++;
931                                 continue;
932                         }
933                         fl = fopen(fname, "w");
934                         if (!fl) {
935                                 fprintf(stderr, "Cannot create %s: %s\n",
936                                         fname, strerror(errno));
937                                 errs++;
938                                 continue;
939                         }
940                         code_node_print(fl, s->code, argv[1]);
941                         fclose(fl);
942                 }
943                 exit(!!errs);
944         }
945