from __future__ import division
from __future__ import print_function
from __future__ import unicode_literals
import re
import sys
try:
xrange except NameError:
xrange = range
SKIP_FILES = [ "OpenBSD_malloc_Linux.c",
"strlcat.c",
"strlcpy.c",
"sha256.c",
"sha256.h",
"aes.c",
"aes.h" ]
SKIP_NAME_PATTERNS = [ r'^.*_c_id$',
r'^.*_H_ID$' ]
ADD_DOCDOCS_TO_TYPES = [ 'function', 'type', 'typedef' ]
ADD_DOCDOCS_TO_TYPES += [ 'variable', ]
KINDS = [ "type", "field", "typedef", "define", "function", "variable",
"enumeration" ]
NODOC_LINE_RE = re.compile(r'^([^:]+):(\d+): (\w+): (.*) is not documented\.$')
THING_RE = re.compile(r'^Member ([a-zA-Z0-9_]+).*\((typedef|define|function|variable|enumeration|macro definition)\) of (file|class) ')
SKIP_NAMES = [re.compile(s) for s in SKIP_NAME_PATTERNS]
def parsething(thing):
if thing.startswith("Compound "):
tp, name = "type", thing.split()[1]
else:
m = THING_RE.match(thing)
if not m:
print(thing, "???? Format didn't match.")
return None, None
else:
name, tp, parent = m.groups()
if parent == 'class':
if tp == 'variable' or tp == 'function':
tp = 'field'
return name, tp
def read():
errs = {}
for line in sys.stdin:
m = NODOC_LINE_RE.match(line)
if m:
file, line, tp, thing = m.groups()
assert tp.lower() == 'warning'
name, kind = parsething(thing)
errs.setdefault(file, []).append((int(line), name, kind))
return errs
def findline(lines, lineno, ident):
lno = lineno
for lineno in xrange(lineno, 0, -1):
try:
if ident in lines[lineno]:
return lineno
except IndexError:
continue
return None
FUNC_PAT = re.compile(r"^[A-Za-z0-9_]+\(")
def hascomment(lines, lineno, kind):
if "*/" in lines[lineno-1]:
return True
if kind == 'function' and FUNC_PAT.match(lines[lineno]):
if "*/" in lines[lineno-2]:
return True
return False
def hasdocdoc(lines, lineno, kind):
try:
if "DOCDOC" in lines[lineno]:
return True
except IndexError:
pass
try:
if "DOCDOC" in lines[lineno-1]:
return True
except IndexError:
pass
if kind == 'function' and FUNC_PAT.match(lines[lineno]):
if "DOCDOC" in lines[lineno-2]:
return True
return False
def checkf(fn, errs):
for skip in SKIP_FILES:
if fn.endswith(skip):
print("Skipping",fn)
return
comments = []
lines = [ None ]
try:
lines.extend( open(fn, 'r').readlines() )
except IOError:
return
for line, name, kind in errs:
if any(pat.match(name) for pat in SKIP_NAMES):
continue
if kind not in ADD_DOCDOCS_TO_TYPES:
continue
ln = findline(lines, line, name)
if ln == None:
print("Couldn't find the definition of %s allegedly on %s of %s"%(
name, line, fn))
else:
if hasdocdoc(lines, line, kind):
pass
else:
if kind == 'function' and FUNC_PAT.match(lines[ln]):
ln = ln - 1
comments.append((ln, kind, name))
return comments
def applyComments(fn, entries):
N = 0
lines = [ None ]
try:
lines.extend( open(fn, 'r').readlines() )
except IOError:
return
entries.sort()
entries.reverse()
for ln, kind, name in entries:
lines.insert(ln, "/* DOCDOC %s */\n"%name)
N += 1
outf = open(fn+".newdoc", 'w')
for line in lines[1:]:
outf.write(line)
outf.close()
print("Added %s DOCDOCs to %s" %(N, fn))
e = read()
for fn, errs in e.iteritems():
print(repr((fn, errs)))
comments = checkf(fn, errs)
if comments:
applyComments(fn, comments)