aboutsummaryrefslogtreecommitdiff
path: root/lib/cmark/man/make_man_page.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/cmark/man/make_man_page.py')
-rw-r--r--lib/cmark/man/make_man_page.py133
1 files changed, 133 insertions, 0 deletions
diff --git a/lib/cmark/man/make_man_page.py b/lib/cmark/man/make_man_page.py
new file mode 100644
index 0000000..4b49dbd
--- /dev/null
+++ b/lib/cmark/man/make_man_page.py
@@ -0,0 +1,133 @@
+#!/usr/bin/env python
+
+# Creates a man page from a C file.
+
+# first argument if present is path to cmark dynamic library
+
+# Comments beginning with `/**` are treated as Groff man, except that
+# 'this' is converted to \fIthis\f[], and ''this'' to \fBthis\f[].
+
+# 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, re, os, platform
+from datetime import date
+from ctypes import CDLL, c_char_p, c_long, c_void_p
+
+sysname = platform.system()
+
+if sysname == 'Darwin':
+ cmark = CDLL("build/src/libcmark.dylib")
+else:
+ cmark = CDLL("build/src/libcmark.so")
+
+parse_document = cmark.cmark_parse_document
+parse_document.restype = c_void_p
+parse_document.argtypes = [c_char_p, c_long]
+
+render_man = cmark.cmark_render_man
+render_man.restype = c_char_p
+render_man.argtypes = [c_void_p, c_long, c_long]
+
+def md2man(text):
+ if sys.version_info >= (3,0):
+ textbytes = text.encode('utf-8')
+ textlen = len(textbytes)
+ return render_man(parse_document(textbytes, textlen), 0, 65).decode('utf-8')
+ else:
+ textbytes = text
+ textlen = len(text)
+ return render_man(parse_document(textbytes, textlen), 0, 72)
+
+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('}')
+single_quote_re = re.compile("(?<!\w)'([^']+)'(?!\w)")
+double_quote_re = re.compile("(?<!\w)''([^']+)''(?!\w)")
+
+def handle_quotes(s):
+ return re.sub(double_quote_re, '**\g<1>**', re.sub(single_quote_re, '*\g<1>*', s))
+
+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 = 'man'
+ elif comment_end_re.match(line) and state == 'man':
+ continue
+ elif comment_delim_re.match(line) and state == 'man':
+ state = 'man'
+ elif not typedef and blank_re.match(line):
+ state = 'default'
+ elif typedef and typedef_end_re.match(line):
+ typedef = False
+ elif typedef_start_re.match(line):
+ typedef = True
+ state = 'signature'
+ elif state == 'man':
+ state = 'signature'
+
+ # handle line
+ if state == 'man':
+ chunk.append(handle_quotes(re.sub(comment_delim_re, '', line)))
+ elif state == 'signature':
+ ln = re.sub(macro_re, '', line)
+ 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')
+ rawsig = ''.join(sig)
+ m = function_re.match(rawsig)
+ mdlines.append('.PP\n')
+ if m:
+ mdlines.append('\\fI' + m.group('type') + '\\f[]' + ' ')
+ mdlines.append('\\fB' + m.group('name') + '\\f[]' + '(')
+ first = True
+ for argument in re.split(',', m.group('args')):
+ if not first:
+ mdlines.append(', ')
+ first = False
+ mdlines.append('\\fI' + argument.strip() + '\\f[]')
+ mdlines.append(')\n')
+ else:
+ mdlines.append('.nf\n\\fC\n.RS 0n\n')
+ mdlines += sig
+ mdlines.append('.RE\n\\f[]\n.fi\n')
+ if len(mdlines) > 0 and mdlines[-1] != '\n':
+ mdlines.append('\n')
+ mdlines += md2man(''.join(chunk))
+ mdlines.append('\n')
+ chunk = []
+ sig = []
+ elif oldstate == 'man' and state != 'signature':
+ if len(mdlines) > 0 and mdlines[-1] != '\n':
+ mdlines.append('\n')
+ mdlines += md2man(''.join(chunk)) # add man chunk
+ chunk = []
+ mdlines.append('\n')
+
+sys.stdout.write('.TH ' + os.path.basename(sourcefile).replace('.h','') + ' 3 "' + date.today().strftime('%B %d, %Y') + '" "LOCAL" "Library Functions Manual"\n')
+sys.stdout.write(''.join(mdlines))