Commit 09ceb381 authored by ASN.1 Documenter's avatar ASN.1 Documenter
Browse files

skip empty fields

:# Please enter the commit message for your changes. Lines starting
parent 5ce13e12
Loading
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -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 $@
+74 −58
Original line number Diff line number Diff line
@@ -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)

@@ -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)
@@ -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 + '&nbsp;&nbsp;&nbsp;&nbsp;**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 + '&nbsp;&nbsp;&nbsp;&nbsp;**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 + '&nbsp;&nbsp;&nbsp;&nbsp;**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
@@ -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
@@ -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)
@@ -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&nbsp;&nbsp;&nbsp;&nbsp;**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&nbsp;&nbsp;&nbsp;&nbsp;**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 '&nbsp;&nbsp;&nbsp;&nbsp;**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:
@@ -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):
@@ -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
@@ -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()