Loading .gitlab-ci.mk +1 −1 Original line number Diff line number Diff line Loading @@ -15,7 +15,7 @@ endif validate: iso build doc: docs python3 asn2md.py -o docs $(ASN1_SRC) python3 asn2md.py -o docs --no-empty-fields $(ASN1_SRC) iso docs: mkdir -p $@ Loading asn2md.py +74 −58 Original line number Diff line number Diff line Loading @@ -46,7 +46,7 @@ RE_DOXY_STRIP_TAG = re.compile(r'\s*@(?:class|struct):?\s+[\w-]+') RE_DOXY_UNIT = re.compile(r'^\s*@unit:?\s+(.+)\n+', re.MULTILINE) RE_DOXY_BRIEF = re.compile(r'^\s*@brief:?\s+(.+)\n+', re.MULTILINE) RE_DOXY_CATEGORY = re.compile(r'@category:\s+(.+)\n+', re.MULTILINE) RE_DOXY_NOTE = re.compile(r'@note:\s+(.+)\n+', re.MULTILINE) RE_DOXY_NOTE = re.compile(r'@note\s*(\d*):\s+(.+?)\n\s*$', re.MULTILINE | re.DOTALL) RE_DOXY_PARAM = re.compile(r'^\s*@(?:param|field|value)\s+([\w-]+):?\s*(.*?)\n\s*$', re.MULTILINE | re.DOTALL) RE_DOXY_OPTION = re.compile(r'@(no-auto-fields|no-auto-values)', re.MULTILINE) Loading @@ -64,9 +64,6 @@ def urlquote(s): return urllib.quote_plus(s) def parseText(content, indent=None): strIndent = ''.ljust(indent or 0) def repl_ref(m): return '[**{0}**]({1}#{0})'.format(m.group(1), extTypes.get(m.group(1),'')) content = RE_DOXY_REF.sub(repl_ref, content) Loading @@ -75,35 +72,7 @@ def parseText(content, indent=None): content = RE_DOXY_STRIP_SINGLE_TAG.sub('', content) def repl_category(m): ret = '\n' + strIndent + ' **Categories**: ' for l in m.group(1).split(','): ret += '[{0}](#{1}) '.format(l.strip(), urlquote(l.strip())) return ret + '\n\n' content = RE_DOXY_CATEGORY.sub(repl_category, content) s_unit='' def repl_unit(m): nonlocal s_unit s_unit = '<br>' + strIndent + ' **Unit**: _' + m.group(1).strip() + '_\n\n' return '' content = RE_DOXY_UNIT.sub(repl_unit, content) s_category='' def repl_category(m): nonlocal s_category s_category = '<br>' + strIndent + ' **Categories**: ' for l in m.group(1).split(','): s_category += '_[{0}](#{1})_ '.format(l.strip(), urlquote(l.strip())) s_category += '\n\n' return '' content = RE_DOXY_CATEGORY.sub(repl_category, content) def repl_note(m): return '<br>' + strIndent + ' **NOTE**: ' + m.group(1).strip() + '\n\n' content = RE_DOXY_NOTE.sub(repl_note, content) return content + s_unit + s_category return content def parseInlineComments(content:str, indent=None): # keep into account only '--<' comments Loading @@ -129,7 +98,7 @@ def parseDoxyComments(content:str, indent=None): for l in lines: l = l.strip().lstrip('*') ret += ''.ljust(indent or 0) + l + '\n' return parseText(ret, indent) return ret def parseModule(mname, content): global cpos Loading Loading @@ -160,7 +129,16 @@ def parseModule(mname, content): def repl_type (m, doc): title = t = m.group(1) auto_fields = True s_unit = '' s_category = '' s_params = {} if doc : # non None and not empty # keep only doxy comments doc = parseDoxyComments(doc) # parse @brief def repl_brief (m): nonlocal title title = m.group(1) Loading @@ -168,30 +146,54 @@ def parseModule(mname, content): if o_args.brief_as_title: doc = RE_DOXY_BRIEF.sub(repl_brief, doc, 1) # parse options def repl_doxy_option(m): nonlocal auto_fields if m.group(1) == 'no-auto-fields' or m.group(1) == 'no-auto-values': auto_fields = False return '' doc = RE_DOXY_OPTION.sub(repl_doxy_option, doc) doc = parseDoxyComments(doc) + '\n\n' else: doc = '' ret = '' if t is not None: # parse out @params f_params = {} # filter out unit def repl_unit(m): nonlocal s_unit s_unit = '\n\n **Unit**: _{}_'.format(m.group(1).strip()) return '' doc = RE_DOXY_UNIT.sub(repl_unit, doc, 1) #filter out category def repl_category(m): nonlocal s_category s_category = '\n\n **Categories**: ' for l in m.group(1).split(','): l = l.strip() if l: s_category += '_[{0}](#{1})_ '.format(l, urlquote(l)) return '' doc = RE_DOXY_CATEGORY.sub(repl_category, doc, 1) #filter out notes def repl_note(m): return ' **NOTE{0}**: {1}\n{2}\n\n'.format(m.group(1) or '', m.group(2).strip(), "{: .note}") doc = RE_DOXY_NOTE.sub(repl_note, doc) #filter out params def repl_param (m): nonlocal f_params nonlocal s_params if m.group(1) is not None and m.group(2) is not None: l = m.group(2).lstrip(":, \t\n") l = parseText(m.group(2).lstrip(":, \t\n")) if len(l): f_params[m.group(1)] = l s_params[m.group(1)] = l return '' doc = RE_DOXY_PARAM.sub(repl_param, doc) ret = '### <a name="{0}"></a>{1}\n\n'.format(t, title) + doc doc = parseText(doc).strip() + s_unit + s_category else: doc = '' ret = '' if t is not None: ret = '### <a name="{0}"></a>{1}\n\n'.format(t, title) + doc + '\n\n' # parse fields and get out fields descriptions if m.group(3) is not None: Loading @@ -202,31 +204,42 @@ def parseModule(mname, content): if typeBody is not None: fTitle = '' fields = '' f_header = '' f_doc = '' pos = 0 for fm in RE_FIELDS.finditer(typeBody): f_doc += parseInlineComments(fm.string[pos:fm.start()], 3).strip() if f_header and (f_doc or not o_args.no_empty_fields): fields += f_header + ( f_doc or '\n' ) f_doc = '' if fm.group(1) is not None: # add description to the previous type fields += parseInlineComments(fm.string[pos:fm.start()], 3) f = fm.group(1).strip() ext = fm.group(3) or '' if fm.group(2) is not None: fTitle = 'Fields:\n' t = fm.group(2).strip() if RE_BASIC_TYPES.match(t) is not None: fields += '* {0} **{1}** {2}<br>\n'.format(f, t, ext) f_header = '* {0} **{1}** {2}<br>\n'.format(f, t, ext) else: fields += '* {0} [**{1}**]({2}#{1}) {3}<br>\n'.format(f, t, extTypes.get(t,''), ext) f_header += '* {0} [**{1}**]({2}#{1}) {3}<br>\n'.format(f, t, extTypes.get(t,''), ext) else: fTitle = 'Values:\n' fields += '* **{0}** {1}<br>\n'.format(f, ext) if f in f_params: fields += f_params[f] + '\n\n' fields += parseDoxyComments(fm.string[pos:fm.start()], 3) f_header = '* **{0}** {1}<br>\n'.format(f, ext) if f in s_params: f_doc = s_params[f] + '\n\n' f = parseDoxyComments(fm.string[pos:fm.start()], 3).strip() if f: f_doc += f + '\n\n' pos = fm.end() if fm.group(4) is not None: # keep '--' for the next round pos -= 2 fields += parseInlineComments(typeBody[pos:], 3) f_doc += parseInlineComments(typeBody[pos:], 3).strip() if f_doc or not o_args.no_empty_fields: fields += f_header + ( f_doc or '\n' ) ret = ret.strip() + '\n\n' if auto_fields and len(fields): Loading @@ -234,7 +247,8 @@ def parseModule(mname, content): else: if title: ret = '### {}\n\n'.format(title) ret += parseDoxyComments(doc) + '\n\n' ret += doc + '\n\n' return ret + '```asn1\n' + RE_COMMENTS.sub('', m.group(0).strip()) +'\n```\n\n' pos = 0 Loading Loading @@ -265,6 +279,8 @@ def main(): ap = argparse.ArgumentParser(description='ASN.1 to markdown converter') ap.add_argument('--out', '-o', type=str, default='.', help='output directory') ap.add_argument('--brief-as-title', '-B', default=False, action='store_true', help='Do not treat @brief line as type header') ap.add_argument('--no-empty-fields', '-F', default=False, action='store_true', help='Do not add non-documented fields in the "Fields" block') ap.add_argument('--no-empty-values', '-V', default=False, action='store_true', help='Do not add non-documented fields in the "Fields" block') ap.add_argument('modules', action='store', nargs='+', help='ASN.1 files') o_args = ap.parse_args() Loading Loading
.gitlab-ci.mk +1 −1 Original line number Diff line number Diff line Loading @@ -15,7 +15,7 @@ endif validate: iso build doc: docs python3 asn2md.py -o docs $(ASN1_SRC) python3 asn2md.py -o docs --no-empty-fields $(ASN1_SRC) iso docs: mkdir -p $@ Loading
asn2md.py +74 −58 Original line number Diff line number Diff line Loading @@ -46,7 +46,7 @@ RE_DOXY_STRIP_TAG = re.compile(r'\s*@(?:class|struct):?\s+[\w-]+') RE_DOXY_UNIT = re.compile(r'^\s*@unit:?\s+(.+)\n+', re.MULTILINE) RE_DOXY_BRIEF = re.compile(r'^\s*@brief:?\s+(.+)\n+', re.MULTILINE) RE_DOXY_CATEGORY = re.compile(r'@category:\s+(.+)\n+', re.MULTILINE) RE_DOXY_NOTE = re.compile(r'@note:\s+(.+)\n+', re.MULTILINE) RE_DOXY_NOTE = re.compile(r'@note\s*(\d*):\s+(.+?)\n\s*$', re.MULTILINE | re.DOTALL) RE_DOXY_PARAM = re.compile(r'^\s*@(?:param|field|value)\s+([\w-]+):?\s*(.*?)\n\s*$', re.MULTILINE | re.DOTALL) RE_DOXY_OPTION = re.compile(r'@(no-auto-fields|no-auto-values)', re.MULTILINE) Loading @@ -64,9 +64,6 @@ def urlquote(s): return urllib.quote_plus(s) def parseText(content, indent=None): strIndent = ''.ljust(indent or 0) def repl_ref(m): return '[**{0}**]({1}#{0})'.format(m.group(1), extTypes.get(m.group(1),'')) content = RE_DOXY_REF.sub(repl_ref, content) Loading @@ -75,35 +72,7 @@ def parseText(content, indent=None): content = RE_DOXY_STRIP_SINGLE_TAG.sub('', content) def repl_category(m): ret = '\n' + strIndent + ' **Categories**: ' for l in m.group(1).split(','): ret += '[{0}](#{1}) '.format(l.strip(), urlquote(l.strip())) return ret + '\n\n' content = RE_DOXY_CATEGORY.sub(repl_category, content) s_unit='' def repl_unit(m): nonlocal s_unit s_unit = '<br>' + strIndent + ' **Unit**: _' + m.group(1).strip() + '_\n\n' return '' content = RE_DOXY_UNIT.sub(repl_unit, content) s_category='' def repl_category(m): nonlocal s_category s_category = '<br>' + strIndent + ' **Categories**: ' for l in m.group(1).split(','): s_category += '_[{0}](#{1})_ '.format(l.strip(), urlquote(l.strip())) s_category += '\n\n' return '' content = RE_DOXY_CATEGORY.sub(repl_category, content) def repl_note(m): return '<br>' + strIndent + ' **NOTE**: ' + m.group(1).strip() + '\n\n' content = RE_DOXY_NOTE.sub(repl_note, content) return content + s_unit + s_category return content def parseInlineComments(content:str, indent=None): # keep into account only '--<' comments Loading @@ -129,7 +98,7 @@ def parseDoxyComments(content:str, indent=None): for l in lines: l = l.strip().lstrip('*') ret += ''.ljust(indent or 0) + l + '\n' return parseText(ret, indent) return ret def parseModule(mname, content): global cpos Loading Loading @@ -160,7 +129,16 @@ def parseModule(mname, content): def repl_type (m, doc): title = t = m.group(1) auto_fields = True s_unit = '' s_category = '' s_params = {} if doc : # non None and not empty # keep only doxy comments doc = parseDoxyComments(doc) # parse @brief def repl_brief (m): nonlocal title title = m.group(1) Loading @@ -168,30 +146,54 @@ def parseModule(mname, content): if o_args.brief_as_title: doc = RE_DOXY_BRIEF.sub(repl_brief, doc, 1) # parse options def repl_doxy_option(m): nonlocal auto_fields if m.group(1) == 'no-auto-fields' or m.group(1) == 'no-auto-values': auto_fields = False return '' doc = RE_DOXY_OPTION.sub(repl_doxy_option, doc) doc = parseDoxyComments(doc) + '\n\n' else: doc = '' ret = '' if t is not None: # parse out @params f_params = {} # filter out unit def repl_unit(m): nonlocal s_unit s_unit = '\n\n **Unit**: _{}_'.format(m.group(1).strip()) return '' doc = RE_DOXY_UNIT.sub(repl_unit, doc, 1) #filter out category def repl_category(m): nonlocal s_category s_category = '\n\n **Categories**: ' for l in m.group(1).split(','): l = l.strip() if l: s_category += '_[{0}](#{1})_ '.format(l, urlquote(l)) return '' doc = RE_DOXY_CATEGORY.sub(repl_category, doc, 1) #filter out notes def repl_note(m): return ' **NOTE{0}**: {1}\n{2}\n\n'.format(m.group(1) or '', m.group(2).strip(), "{: .note}") doc = RE_DOXY_NOTE.sub(repl_note, doc) #filter out params def repl_param (m): nonlocal f_params nonlocal s_params if m.group(1) is not None and m.group(2) is not None: l = m.group(2).lstrip(":, \t\n") l = parseText(m.group(2).lstrip(":, \t\n")) if len(l): f_params[m.group(1)] = l s_params[m.group(1)] = l return '' doc = RE_DOXY_PARAM.sub(repl_param, doc) ret = '### <a name="{0}"></a>{1}\n\n'.format(t, title) + doc doc = parseText(doc).strip() + s_unit + s_category else: doc = '' ret = '' if t is not None: ret = '### <a name="{0}"></a>{1}\n\n'.format(t, title) + doc + '\n\n' # parse fields and get out fields descriptions if m.group(3) is not None: Loading @@ -202,31 +204,42 @@ def parseModule(mname, content): if typeBody is not None: fTitle = '' fields = '' f_header = '' f_doc = '' pos = 0 for fm in RE_FIELDS.finditer(typeBody): f_doc += parseInlineComments(fm.string[pos:fm.start()], 3).strip() if f_header and (f_doc or not o_args.no_empty_fields): fields += f_header + ( f_doc or '\n' ) f_doc = '' if fm.group(1) is not None: # add description to the previous type fields += parseInlineComments(fm.string[pos:fm.start()], 3) f = fm.group(1).strip() ext = fm.group(3) or '' if fm.group(2) is not None: fTitle = 'Fields:\n' t = fm.group(2).strip() if RE_BASIC_TYPES.match(t) is not None: fields += '* {0} **{1}** {2}<br>\n'.format(f, t, ext) f_header = '* {0} **{1}** {2}<br>\n'.format(f, t, ext) else: fields += '* {0} [**{1}**]({2}#{1}) {3}<br>\n'.format(f, t, extTypes.get(t,''), ext) f_header += '* {0} [**{1}**]({2}#{1}) {3}<br>\n'.format(f, t, extTypes.get(t,''), ext) else: fTitle = 'Values:\n' fields += '* **{0}** {1}<br>\n'.format(f, ext) if f in f_params: fields += f_params[f] + '\n\n' fields += parseDoxyComments(fm.string[pos:fm.start()], 3) f_header = '* **{0}** {1}<br>\n'.format(f, ext) if f in s_params: f_doc = s_params[f] + '\n\n' f = parseDoxyComments(fm.string[pos:fm.start()], 3).strip() if f: f_doc += f + '\n\n' pos = fm.end() if fm.group(4) is not None: # keep '--' for the next round pos -= 2 fields += parseInlineComments(typeBody[pos:], 3) f_doc += parseInlineComments(typeBody[pos:], 3).strip() if f_doc or not o_args.no_empty_fields: fields += f_header + ( f_doc or '\n' ) ret = ret.strip() + '\n\n' if auto_fields and len(fields): Loading @@ -234,7 +247,8 @@ def parseModule(mname, content): else: if title: ret = '### {}\n\n'.format(title) ret += parseDoxyComments(doc) + '\n\n' ret += doc + '\n\n' return ret + '```asn1\n' + RE_COMMENTS.sub('', m.group(0).strip()) +'\n```\n\n' pos = 0 Loading Loading @@ -265,6 +279,8 @@ def main(): ap = argparse.ArgumentParser(description='ASN.1 to markdown converter') ap.add_argument('--out', '-o', type=str, default='.', help='output directory') ap.add_argument('--brief-as-title', '-B', default=False, action='store_true', help='Do not treat @brief line as type header') ap.add_argument('--no-empty-fields', '-F', default=False, action='store_true', help='Do not add non-documented fields in the "Fields" block') ap.add_argument('--no-empty-values', '-V', default=False, action='store_true', help='Do not add non-documented fields in the "Fields" block') ap.add_argument('modules', action='store', nargs='+', help='ASN.1 files') o_args = ap.parse_args() Loading