cmark

My personal build of CMark ✏️

Commit
75be85f77f02c8185e8fff607bf3ccf3c8fe3a11
Parent
7686b7dad5c80d494b993158def220aa8b61ac6e
Author
John MacFarlane <jgm@berkeley.edu>
Date

Create man 3 page without markdown intermediary.

Use proper man style, marking function types, arguments, etc.

See #224.

Diffstat

4 files changed, 329 insertions, 200 deletions

Status File Name N° Changes Insertions Deletions
Modified Makefile 5 1 4
Modified man/make_man_page.py 68 44 24
Modified man/man3/cmark.3 428 268 160
Modified src/cmark.h 28 16 12
diff --git a/Makefile b/Makefile
@@ -74,10 +74,7 @@ $(PROG): all
 man/man1/cmark.1: man/cmark.1.md
 	mkdir -p man/man1 && pandoc -t man -s $< -o $@
 
-man/man3/cmark.3: man/cmark.3.md
-	mkdir -p man/man3 && pandoc -t man -s $< -o $@
-
-man/cmark.3.md: src/cmark.h
+man/man3/cmark.3: src/cmark.h
 	python man/make_man_page.py $< > $@
 
 # We include html_unescape.h in the repository, so this shouldn't
diff --git a/man/make_man_page.py b/man/make_man_page.py
@@ -2,71 +2,91 @@
 
 # Creates a man page from a C file.
 
-# Comments beginning with `/**` are treated as Markdown.
+# Comments beginning with `/**` are treated as Groff man.
 
-# Non-blank lines immediately following a Markdown comment are treated
-# as function signatures or examples and included verbatim. The
-# immediately preceding markdown chunk is printed after the example
+# Non-blank lines immediately following a man page comment are treated
+# as function signatures or examples and parsed into .Ft, .Fo, .Fa, .Fc. The
+# immediately preceding man documentation chunk is printed after the example
 # as a comment on it.
 
 # That's about it!
 
-import sys
-import re
-
-if len(sys.argv) > 1:
-    sourcefile = sys.argv[1]
-else:
-    print("Usage:  make_man_page.py sourcefile")
-    exit(1)
+import sys, re, os
+from datetime import date
 
 comment_start_re = re.compile('^\/\*\* ?')
 comment_delim_re = re.compile('^[/ ]\** ?')
 comment_end_re = re.compile('^ \**\/')
+function_re = re.compile('^ *(?:CMARK_EXPORT\s+)?(?P<type>(?:const\s+)?\w+(?:\s*[*])?)\s*(?P<name>\w+)\s*\((?P<args>[^)]*)\)')
 blank_re = re.compile('^\s*$')
 macro_re = re.compile('CMARK_EXPORT *')
+typedef_start_re = re.compile('typedef.*{$')
+typedef_end_re = re.compile('}')
 
+typedef = False
 mdlines = []
 chunk = []
 sig = []
 
+if len(sys.argv) > 1:
+    sourcefile = sys.argv[1]
+else:
+    print("Usage:  make_man_page.py sourcefile")
+    exit(1)
+
 with open(sourcefile, 'r') as cmarkh:
     state = 'default'
     for line in cmarkh:
         # state transition
         oldstate = state
         if comment_start_re.match(line):
-            state = 'markdown'
-        elif comment_end_re.match(line) and state == 'markdown':
+            state = 'man'
+        elif comment_end_re.match(line) and state == 'man':
             continue
-        elif comment_delim_re.match(line) and state == 'markdown':
-            state = 'markdown'
-        elif blank_re.match(line):
+        elif comment_delim_re.match(line) and state == 'man':
+            state = 'man'
+        elif not typedef and blank_re.match(line):
             state = 'default'
-        elif state == 'markdown':
+        elif typedef and typedef_end_re.match(line):
+            typedef = False
+        elif state == 'man':
             state = 'signature'
+            typedef = typedef_start_re.match(line)
 
         # handle line
-        if state == 'markdown':
+        if state == 'man':
             chunk.append(re.sub(comment_delim_re, '', line))
         elif state == 'signature':
             ln = re.sub(macro_re, '', line)
-            if not re.match(blank_re, ln):
-                sig.append('    ' + ln)
+            if typedef or not re.match(blank_re, ln):
+                sig.append(ln)
         elif oldstate == 'signature' and state != 'signature':
             if len(mdlines) > 0 and mdlines[-1] != '\n':
                 mdlines.append('\n')
-            mdlines += sig   # add sig, then prepended markdown comment
+            rawsig = ''.join(sig)
+            m = function_re.match(rawsig)
+            if m:
+                mdlines.append('.Ft ' + m.group('type') + '\n')
+                mdlines.append('.Fo ' + m.group('name') + '\n')
+                for argument in re.split('/s*,/s*', m.group('args')):
+                    mdlines.append('.Fa ' + argument + '\n')
+                mdlines.append('.Fc\n')
+            else:
+                mdlines.append('.Bd -literal\n')
+                mdlines += sig
+                mdlines.append('.Ed\n')
             if len(mdlines) > 0 and mdlines[-1] != '\n':
                 mdlines.append('\n')
             mdlines += chunk
             chunk = []
             sig = []
-        elif oldstate == 'markdown' and state != 'signature':
+        elif oldstate == 'man' and state != 'signature':
             if len(mdlines) > 0 and mdlines[-1] != '\n':
                 mdlines.append('\n')
-            mdlines += chunk # add markdown chunk
+            mdlines += chunk # add man chunk
             chunk = []
             mdlines.append('\n')
 
+sys.stdout.write('.Dd ' + date.today().isoformat() + '\n')
+sys.stdout.write('.Dt ' + os.path.basename(sourcefile) + '\n')
 sys.stdout.write(''.join(mdlines))
diff --git a/man/man3/cmark.3 b/man/man3/cmark.3
@@ -1,233 +1,341 @@
-.TH "" "" "" "" ""
-.SH NAME
-.PP
-cmark \- CommonMark parsing, manipulating, and rendering
-.SH SIMPLE INTERFACE
-.IP
-.nf
-\f[C]
-#define\ CMARK_VERSION\ "0.1"
-\f[]
-.fi
-.PP
+.Dd 2014-11-30
+.Dt cmark.h
+.Sh NAME
+
+.Nm cmark
+.Nd CommonMark parsing, manipulating, and rendering
+
+.Sh SIMPLE INTERFACE
+
+.Bd -literal
+#define CMARK_VERSION "0.1"
+.Ed
+
 Current version of library.
-.IP
-.nf
-\f[C]
-char\ *cmark_markdown_to_html(const\ char\ *text,\ int\ len);
-\f[]
-.fi
-.PP
-Convert \f[C]text\f[] (assumed to be a UTF\-8 encoded string with length
-\f[C]len\f[]) from CommonMark Markdown to HTML, returning a
-null\-terminated, UTF\-8\-encoded string.
-.SH NODE STRUCTURE
-.IP
-.nf
-\f[C]
-typedef\ enum\ {
-\ \ \ \ /*\ Block\ */
-\ \ \ \ CMARK_NODE_DOCUMENT,
-\ \ \ \ CMARK_NODE_BLOCK_QUOTE,
-\ \ \ \ CMARK_NODE_LIST,
-\ \ \ \ CMARK_NODE_LIST_ITEM,
-\ \ \ \ CMARK_NODE_CODE_BLOCK,
-\ \ \ \ CMARK_NODE_HTML,
-\ \ \ \ CMARK_NODE_PARAGRAPH,
-\ \ \ \ CMARK_NODE_HEADER,
-\ \ \ \ CMARK_NODE_HRULE,
-\ \ \ \ CMARK_NODE_REFERENCE_DEF,
+
+.Ft char *
+.Fo cmark_markdown_to_html
+.Fa const char *text, int len
+.Fc
+
+Convert
+.Fa text
+(assumed to be a UTF-8 encoded string with length
+.Fa len )
+from CommonMark Markdown to HTML, returning a null-terminated,
+UTF-8-encoded string.
+
+.Sh NODE STRUCTURE
+
+.Bd -literal
+typedef enum {
+	/* Block */
+	CMARK_NODE_DOCUMENT,
+	CMARK_NODE_BLOCK_QUOTE,
+	CMARK_NODE_LIST,
+	CMARK_NODE_LIST_ITEM,
+	CMARK_NODE_CODE_BLOCK,
+	CMARK_NODE_HTML,
+	CMARK_NODE_PARAGRAPH,
+	CMARK_NODE_HEADER,
+	CMARK_NODE_HRULE,
+	CMARK_NODE_REFERENCE_DEF,
+
+	CMARK_NODE_FIRST_BLOCK = CMARK_NODE_DOCUMENT,
+	CMARK_NODE_LAST_BLOCK  = CMARK_NODE_REFERENCE_DEF,
+
+	/* Inline */
+	CMARK_NODE_TEXT,
+	CMARK_NODE_SOFTBREAK,
+	CMARK_NODE_LINEBREAK,
+	CMARK_NODE_INLINE_CODE,
+	CMARK_NODE_INLINE_HTML,
+	CMARK_NODE_EMPH,
+	CMARK_NODE_STRONG,
+	CMARK_NODE_LINK,
+	CMARK_NODE_IMAGE,
+
+	CMARK_NODE_FIRST_INLINE = CMARK_NODE_TEXT,
+	CMARK_NODE_LAST_INLINE  = CMARK_NODE_IMAGE,
+} cmark_node_type;
+.Ed
+
+
+.Bd -literal
+typedef enum {
+	CMARK_NO_LIST,
+	CMARK_BULLET_LIST,
+	CMARK_ORDERED_LIST
+}  cmark_list_type;
+.Ed
+
+
+.Bd -literal
+typedef enum {
+	CMARK_PERIOD_DELIM,
+	CMARK_PAREN_DELIM
+} cmark_delim_type;
+.Ed
+
+
+
+.Sh CREATING AND DESTORYING NODES
+
+.Ft cmark_node*
+.Fo cmark_node_new
+.Fa cmark_node_type type
+.Fc
+
+
+.Ft void
+.Fo cmark_node_free
+.Fa cmark_node *node
+.Fc
+
+
+.Ft cmark_node*
+.Fo cmark_node_next
+.Fa cmark_node *node
+.Fc
+
+
+.Sh TREE TRAVERSAL
+
+.Ft cmark_node*
+.Fo cmark_node_previous
+.Fa cmark_node *node
+.Fc
+
+
+.Ft cmark_node*
+.Fo cmark_node_parent
+.Fa cmark_node *node
+.Fc
+
+
+.Ft cmark_node*
+.Fo cmark_node_first_child
+.Fa cmark_node *node
+.Fc
+
+
+.Ft cmark_node*
+.Fo cmark_node_last_child
+.Fa cmark_node *node
+.Fc
+
+
+
+.Sh ACCESSORS
+
+.Ft cmark_node_type
+.Fo cmark_node_get_type
+.Fa cmark_node *node
+.Fc
+
+
+.Ft const char*
+.Fo cmark_node_get_string_content
+.Fa cmark_node *node
+.Fc
 
 
-typedef\ enum\ {
-\ \ \ \ CMARK_NO_LIST,
-\ \ \ \ CMARK_BULLET_LIST,
-\ \ \ \ CMARK_ORDERED_LIST
-}\ \ cmark_list_type;
+.Ft int
+.Fo cmark_node_set_string_content
+.Fa cmark_node *node, const char *content
+.Fc
 
 
-typedef\ enum\ {
-\ \ \ \ CMARK_PERIOD_DELIM,
-\ \ \ \ CMARK_PAREN_DELIM
-}\ cmark_delim_type;
-\f[]
-.fi
-.SH CREATING AND DESTORYING NODES
-.IP
-.nf
-\f[C]
-cmark_node*
-cmark_node_new(cmark_node_type\ type);
+.Ft int
+.Fo cmark_node_get_header_level
+.Fa cmark_node *node
+.Fc
 
 
-void
-cmark_node_free(cmark_node\ *node);
+.Ft int
+.Fo cmark_node_set_header_level
+.Fa cmark_node *node, int level
+.Fc
 
 
-cmark_node*
-cmark_node_next(cmark_node\ *node);
-\f[]
-.fi
-.SH TREE TRAVERSAL
-.IP
-.nf
-\f[C]
-cmark_node*
-cmark_node_previous(cmark_node\ *node);
+.Ft cmark_list_type
+.Fo cmark_node_get_list_type
+.Fa cmark_node *node
+.Fc
 
 
-cmark_node*
-cmark_node_parent(cmark_node\ *node);
+.Ft int
+.Fo cmark_node_set_list_type
+.Fa cmark_node *node, cmark_list_type type
+.Fc
 
 
-cmark_node*
-cmark_node_first_child(cmark_node\ *node);
+.Ft int
+.Fo cmark_node_get_list_start
+.Fa cmark_node *node
+.Fc
 
 
-cmark_node*
-cmark_node_last_child(cmark_node\ *node);
-\f[]
-.fi
-.SH ACCESSORS
-.IP
-.nf
-\f[C]
-cmark_node_type
-cmark_node_get_type(cmark_node\ *node);
+.Ft int
+.Fo cmark_node_set_list_start
+.Fa cmark_node *node, int start
+.Fc
 
 
-const\ char*
-cmark_node_get_string_content(cmark_node\ *node);
+.Ft int
+.Fo cmark_node_get_list_tight
+.Fa cmark_node *node
+.Fc
 
 
-int
-cmark_node_set_string_content(cmark_node\ *node,\ const\ char\ *content);
+.Ft int
+.Fo cmark_node_set_list_tight
+.Fa cmark_node *node, int tight
+.Fc
 
 
-int
-cmark_node_get_header_level(cmark_node\ *node);
+.Ft const char*
+.Fo cmark_node_get_fence_info
+.Fa cmark_node *node
+.Fc
 
 
-int
-cmark_node_set_header_level(cmark_node\ *node,\ int\ level);
+.Ft int
+.Fo cmark_node_set_fence_info
+.Fa cmark_node *node, const char *info
+.Fc
 
 
-cmark_list_type
-cmark_node_get_list_type(cmark_node\ *node);
+.Ft const char*
+.Fo cmark_node_get_url
+.Fa cmark_node *node
+.Fc
 
 
-int
-cmark_node_set_list_type(cmark_node\ *node,\ cmark_list_type\ type);
+.Ft int
+.Fo cmark_node_set_url
+.Fa cmark_node *node, const char *url
+.Fc
 
 
-int
-cmark_node_get_list_start(cmark_node\ *node);
+.Ft const char*
+.Fo cmark_node_get_title
+.Fa cmark_node *node
+.Fc
 
 
-int
-cmark_node_set_list_start(cmark_node\ *node,\ int\ start);
+.Ft int
+.Fo cmark_node_set_title
+.Fa cmark_node *node, const char *title
+.Fc
 
 
-int
-cmark_node_get_list_tight(cmark_node\ *node);
+.Ft int
+.Fo cmark_node_get_start_line
+.Fa cmark_node *node
+.Fc
 
 
-int
-cmark_node_set_list_tight(cmark_node\ *node,\ int\ tight);
+.Ft int
+.Fo cmark_node_get_start_column
+.Fa cmark_node *node
+.Fc
 
 
-const\ char*
-cmark_node_get_fence_info(cmark_node\ *node);
+.Ft int
+.Fo cmark_node_get_end_line
+.Fa cmark_node *node
+.Fc
 
 
-int
-cmark_node_set_fence_info(cmark_node\ *node,\ const\ char\ *info);
 
+.Sh TREE MANIPULATION
 
-const\ char*
-cmark_node_get_url(cmark_node\ *node);
+.Ft void
+.Fo cmark_node_unlink
+.Fa cmark_node *node
+.Fc
 
 
-int
-cmark_node_set_url(cmark_node\ *node,\ const\ char\ *url);
+.Ft int
+.Fo cmark_node_insert_before
+.Fa cmark_node *node, cmark_node *sibling
+.Fc
 
 
-const\ char*
-cmark_node_get_title(cmark_node\ *node);
+.Ft int
+.Fo cmark_node_insert_after
+.Fa cmark_node *node, cmark_node *sibling
+.Fc
 
 
-int
-cmark_node_set_title(cmark_node\ *node,\ const\ char\ *title);
+.Ft int
+.Fo cmark_node_prepend_child
+.Fa cmark_node *node, cmark_node *child
+.Fc
 
 
-int
-cmark_node_get_start_line(cmark_node\ *node);
+.Ft int
+.Fo cmark_node_append_child
+.Fa cmark_node *node, cmark_node *child
+.Fc
 
 
-int
-cmark_node_get_start_column(cmark_node\ *node);
 
+.Sh PARSING
 
-int
-cmark_node_get_end_line(cmark_node\ *node);
-\f[]
-.fi
-.SH TREE MANIPULATION
-.IP
-.nf
-\f[C]
-void
-cmark_node_unlink(cmark_node\ *node);
+.Ft cmark_parser *
+.Fo cmark_parser_new
+.Fa 
+.Fc
 
 
-int
-cmark_node_insert_before(cmark_node\ *node,\ cmark_node\ *sibling);
+.Ft void
+.Fo cmark_parser_free
+.Fa cmark_parser *parser
+.Fc
 
 
-int
-cmark_node_insert_after(cmark_node\ *node,\ cmark_node\ *sibling);
+.Ft cmark_node *
+.Fo cmark_parser_finish
+.Fa cmark_parser *parser
+.Fc
 
 
-int
-cmark_node_prepend_child(cmark_node\ *node,\ cmark_node\ *child);
+.Ft void
+.Fo cmark_parser_feed
+.Fa cmark_parser *parser, const char *buffer, size_t len
+.Fc
 
 
-int
-cmark_node_append_child(cmark_node\ *node,\ cmark_node\ *child);
-\f[]
-.fi
-.SH PARSING
-.IP
-.nf
-\f[C]
-cmark_parser\ *cmark_parser_new();
+.Ft cmark_node *
+.Fo cmark_parse_document
+.Fa const char *buffer, size_t len
+.Fc
 
 
-void\ cmark_parser_free(cmark_parser\ *parser);
+.Ft cmark_node *
+.Fo cmark_parse_file
+.Fa FILE *f
+.Fc
 
 
-cmark_node\ *cmark_parser_finish(cmark_parser\ *parser);
 
+.Sh RENDERING
 
-void\ cmark_parser_feed(cmark_parser\ *parser,\ const\ char\ *buffer,\ size_t\ len);
+.Ft char *
+.Fo cmark_render_ast
+.Fa cmark_node *root
+.Fc
 
 
-cmark_node\ *cmark_parse_document(const\ char\ *buffer,\ size_t\ len);
+.Ft char *
+.Fo cmark_render_html
+.Fa cmark_node *root
+.Fc
 
 
-cmark_node\ *cmark_parse_file(FILE\ *f);
-\f[]
-.fi
-.SH RENDERING
-.IP
-.nf
-\f[C]
-char\ *cmark_render_ast(cmark_node\ *root);
+.Sh AUTHORS
 
+John MacFarlane, Vicent Marti,  Kārlis Gaņģis, Nick Wellnhofer.
 
-char\ *cmark_render_html(cmark_node\ *root);
-\f[]
-.fi
-.SH AUTHORS
-.PP
-John MacFarlane, Vicent Marti, Kārlis Gaņģis, Nick Wellnhofer.
diff --git a/src/cmark.h b/src/cmark.h
@@ -8,26 +8,30 @@
 extern "C" {
 #endif
 
-/** # NAME
+/** .Sh NAME
  *
- * cmark - CommonMark parsing, manipulating, and rendering
+ * .Nm cmark
+ * .Nd CommonMark parsing, manipulating, and rendering
  */
 
-/** # SIMPLE INTERFACE
+/** .Sh SIMPLE INTERFACE
  */
 
 /** Current version of library.
  */
 #define CMARK_VERSION "0.1"
 
-/** Convert `text` (assumed to be a UTF-8 encoded string with length `len`)
+/** Convert
+ * .Fa text
+ * (assumed to be a UTF-8 encoded string with length
+ * .Fa len )
  * from CommonMark Markdown to HTML, returning a null-terminated,
  * UTF-8-encoded string.
  */
 CMARK_EXPORT
 char *cmark_markdown_to_html(const char *text, int len);
 
-/** # NODE STRUCTURE
+/** .Sh NODE STRUCTURE
  */
 
 /**
@@ -83,7 +87,7 @@ typedef struct cmark_node cmark_node;
 typedef struct cmark_parser cmark_parser;
 
 /**
- * # CREATING AND DESTORYING NODES
+ * .Sh CREATING AND DESTORYING NODES
  */
 
 /**
@@ -97,7 +101,7 @@ CMARK_EXPORT void
 cmark_node_free(cmark_node *node);
 
 /**
- * # TREE TRAVERSAL
+ * .Sh TREE TRAVERSAL
  */
 CMARK_EXPORT cmark_node*
 cmark_node_next(cmark_node *node);
@@ -123,7 +127,7 @@ CMARK_EXPORT cmark_node*
 cmark_node_last_child(cmark_node *node);
 
 /**
- * # ACCESSORS
+ * .Sh ACCESSORS
  */
 
 /**
@@ -227,7 +231,7 @@ CMARK_EXPORT int
 cmark_node_get_end_line(cmark_node *node);
 
 /**
- * # TREE MANIPULATION
+ * .Sh TREE MANIPULATION
  */
 
 /**
@@ -256,7 +260,7 @@ CMARK_EXPORT int
 cmark_node_append_child(cmark_node *node, cmark_node *child);
 
 /**
- * # PARSING
+ * .Sh PARSING
  */
 
 /**
@@ -290,7 +294,7 @@ CMARK_EXPORT
 cmark_node *cmark_parse_file(FILE *f);
 
 /**
- * # RENDERING
+ * .Sh RENDERING
  */
 
 /**
@@ -303,7 +307,7 @@ char *cmark_render_ast(cmark_node *root);
 CMARK_EXPORT
 char *cmark_render_html(cmark_node *root);
 
-/** # AUTHORS
+/** .Sh AUTHORS
  *
  * John MacFarlane, Vicent Marti,  Kārlis Gaņģis, Nick Wellnhofer.
  */