From 75be85f77f02c8185e8fff607bf3ccf3c8fe3a11 Mon Sep 17 00:00:00 2001 From: John MacFarlane Date: Sun, 30 Nov 2014 12:14:37 -0800 Subject: Create man 3 page without markdown intermediary. Use proper man style, marking function types, arguments, etc. See #224. --- Makefile | 5 +- man/make_man_page.py | 68 +++++--- man/man3/cmark.3 | 428 ++++++++++++++++++++++++++++++++------------------- src/cmark.h | 28 ++-- 4 files changed, 329 insertions(+), 200 deletions(-) diff --git a/Makefile b/Makefile index 6fcc956..a39eb2e 100644 --- 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 index 5ed5b0c..3183397 100644 --- 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(?:const\s+)?\w+(?:\s*[*])?)\s*(?P\w+)\s*\((?P[^)]*)\)') 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 index ded9860..9d24f73 100644 --- 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 index 9e38500..3b789cf 100644 --- 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. */ -- cgit v1.2.3