X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=doclib%2Fpkgdraw;h=35a6b92495ff9e85403fbed67c38b6bf23a5de03;hb=d01f65dcdbb7c26ae07dbcbeca753118d7460225;hp=7bacd98a17da449e9cd762286e12a7d06b4e9ec6;hpb=cb01986c60bd68d43a56e1f648aecd23b43cb893;p=senf.git
diff --git a/doclib/pkgdraw b/doclib/pkgdraw
index 7bacd98..35a6b92 100755
--- a/doclib/pkgdraw
+++ b/doclib/pkgdraw
@@ -107,6 +107,13 @@ def formatPacket(width, fields):
{ 'start': 0, 'size': width, 'skip': True },
{ 'start': 0, 'size': width, 'top': False } ])
start = 0
+ if field.get('optional', False):
+ for area in areas:
+ area['optional'] = True
+ if start > 0 and start < width:
+ areas.append({ 'start': start, 'size': width-start, 'bottom': False,
+ 'right': False})
+ start = 0
if field.get('repeat'):
if start > 0 and start < width:
areas.append({ 'start': start, 'size': width-start, 'bottom': False,
@@ -127,7 +134,7 @@ def formatPacket(width, fields):
# This is a fillup field. Check, wether to draw top:
if len(rows) <= 1:
areas[0]['top'] = False
- elif rows[-2][-1].get('bottom', True):
+ elif rows[-2][-1].get('bottom', True) or not rows[-2][-1].get('right', True):
areas[0]['top'] = False
rows[-1].append(areas.pop(0))
if areas:
@@ -157,11 +164,37 @@ def makeTex(rows):
elif area.get('dots', False):
line.append(r"\wordbox[]{1}{$\vdots$\\[1ex]}")
else:
- line.append(r"\bitbox%s{%s}{\strut %s}"
- % (sides, area['size'], texquote(area.get('name',''))))
+ name = texquote(area.get('name',''))
+ if name and area.get('optional', False):
+ name = "[%s]" % name
+ line.append(r"\bitbox%s{%s}{\strut %s}" % (sides, area['size'], name))
lines.append(" & ".join(line))
return " \\\\\n".join(lines) + "\n"
+COMMENT_RE = re.compile(r'//.*?$|/\*.*?\*/|"(?:\\.|[^\\"])*"', re.S | re.M)
+
+def stripComments(text):
+ def replacer(match):
+ s = match.group(0)
+ if s.startswith('//pkgdraw:'):
+ return "@@" + s[2:]
+ if s.startswith('/'):
+ return ""
+ return s
+ return COMMENT_RE.sub(replacer, text)
+
+SENF_INCLUDE_RE = re.compile(r"#\s*include\s*SENF_")
+
+def quoteMacros(text):
+ return SENF_INCLUDE_RE.sub("PKGDRAW_", text).replace("SENF_PARSER_","PKGDRAW_PARSER_")
+
+def cppExpand(text, cppopts, dir):
+ tmpf = tempfile.NamedTemporaryFile(dir=dir)
+ tmpf.write(text)
+ tmpf.flush()
+ cmd = "gcc %s -E -o - -x c++-header %s" % (" ".join(cppopts), tmpf.name)
+ return os.popen(cmd).read()
+
FIELD_TYPES = {
'UInt8Parser' : {'size': 8 },
'UInt16Parser' : {'size': 16 },
@@ -173,15 +206,24 @@ FIELD_TYPES = {
'Int24Parser' : {'size': 24 },
'Int32Parser' : {'size': 32 },
'Int64Parser' : {'size': 64 },
+ 'UInt16LSBParser' : {'size': 16 },
+ 'UInt24LSBParser' : {'size': 24 },
+ 'UInt32LSBParser' : {'size': 32 },
+ 'UInt64LSBParser' : {'size': 64 },
+ 'Int16LSBParser' : {'size': 16 },
+ 'Int24LSBParser' : {'size': 24 },
+ 'Int32LSBParser' : {'size': 32 },
+ 'Int64LSBParser' : {'size': 64 },
'MACAddressParser': {'size': 48 },
'INet4AddressParser' : {'size': 32 },
'INet6AddressParser' : {'size': 128 },
+ 'VoidPacketParser' : {'size': 0 },
}
def parse_FIELD(args, flags):
args = [ arg.strip() for arg in args.split(',') ]
if len(args) != 2:
- sys.stderr.write("Failed to parse FIELD: %s" % args)
+ sys.stderr.write("Failed to parse FIELD: %s\n" % args)
return None
field = dict(FIELD_TYPES.get(args[1].split(':')[-1], {}))
field['name'] = args[0]
@@ -196,12 +238,12 @@ def parse_FIELD_RO(args, flags):
def parse_BITFIELD(args, flags):
args = [ arg.strip() for arg in args.split(',') ]
if len(args) != 3:
- sys.stderr.write("Failed to parse BITFIELD: %s" % args)
+ sys.stderr.write("Failed to parse BITFIELD: %s\n" % args)
return None
try:
size = int(args[1])
except ValueError:
- sys.stderr.write("Failed to parse BITFIELD: %s" % args)
+ sys.stderr.write("Failed to parse BITFIELD: %s\n" % args)
return None
return { 'size' : size, 'name' : args[0] }
@@ -216,7 +258,7 @@ def parse_SKIP(args, flags):
try:
bytes = int(args.strip())
except ValueError:
- sys.stderr.write("Failed to parse SKIP: %s" % args)
+ sys.stderr.write("Failed to parse SKIP: %s\n" % args)
return None
return { 'size': 8*bytes, 'name': '' }
@@ -224,14 +266,14 @@ def parse_SKIP_BITS(args, flags):
try:
bits = int(args.strip())
except ValueError:
- sys.stderr.write("Failed to parse SKIP_BITS: %s" % args)
+ sys.stderr.write("Failed to parse SKIP_BITS: %s\n" % args)
return None
return { 'size': bits, 'name': '' }
def parse_VECTOR(args, flags):
args = [ arg.strip() for arg in args.split(',') ]
if len(args) < 3:
- sys.stderr.write("Failed to aprse VECTOR: %s" % args)
+ sys.stderr.write("Failed to aprse VECTOR: %s\n" % args)
return None
field = dict(FIELD_TYPES.get(args[-1].split(':')[-1], {}))
field['name'] = args[0]
@@ -241,15 +283,76 @@ def parse_VECTOR(args, flags):
def parse_LIST(args, flags):
return parse_VECTOR(args, flags)
+VARIANT_FIELD_RE_STR = r"""
+ \(\s*(?:
+ ([a-zA-Z0-9_:]+) |
+ id\(\s*
+ [a-zA-Z0-9_]+\s*,\s*
+ (?:
+ ([a-zA-Z0-9_:]+) |
+ key\(\s*[^,]*,\s*([a-zA-Z0-9_:]+)\s*\)
+ )\s*\) |
+ ids\(\s*
+ [a-zA-Z0-9_]+\s*,\s*
+ [a-zA-Z0-9_]+\s*,\s*
+ [a-zA-Z0-9_]+\s*,\s*
+ (?:
+ ([a-zA-Z0-9_:]+) |
+ key\(\s*[^,]*,\s*([a-zA-Z0-9_:]+)\s*\)
+ )\s*\) |
+ novalue\(\s*
+ [a-zA-Z0-9_]+\s*,\s*
+ (?:
+ ([a-zA-Z0-9_:]+) |
+ key\(\s*[^,]*,\s*([a-zA-Z0-9_:]+)\s*\)
+ )\s*\)
+ )\s*\)
+"""
+
+VARIANT_FIELD_RE = re.compile(VARIANT_FIELD_RE_STR, re.X)
+VARIANT_FIELDS_RE = re.compile(",\s*((?:%s\s*)+)$" % VARIANT_FIELD_RE_STR, re.X)
+
def parse_VARIANT(args, flags):
- return { 'name': args.split(',',1)[0].strip() }
+ name = args.split(',',1)[0].strip()
+ fields_match = VARIANT_FIELDS_RE.search(args)
+ if not fields_match:
+ return { 'name': name }
+ fields_str = fields_match.group(1)
+ optional = False
+ minsize = None
+ maxsize = None
+ for field_match in VARIANT_FIELD_RE.finditer(fields_str):
+ parser = ([ group for group in field_match.groups() if group ] + [ None ])[0]
+ field = dict(FIELD_TYPES.get(parser.split(':')[-1], {}))
+ if field.has_key('minsize'):
+ if minsize is None or field['minsize'] < minsize:
+ minsize = field['minsize']
+ if maxsize is None or field['maxsize'] > maxsize:
+ maxsize = field['maxsize']
+ elif field.has_key('size'):
+ if field['size'] == 0:
+ optional = True
+ else:
+ if minsize is None or field['size'] < minsize:
+ minsize = field['size']
+ if maxsize is None or field['size'] > maxsize:
+ maxsize = field['size']
+ if minsize is not None and minsize == maxsize:
+ return { 'name': name, 'size': minsize, 'optional': optional }
+ elif minsize is not None:
+ return { 'name': name, 'minsize': minsize, 'maxsize': maxsize, 'optional': optional }
+ else:
+ return { 'name': name, 'optional': optional }
+
+def parse_PRIVATE_VARIANT(args, flags):
+ return parse_VARIANT(args, flags)
def parse_INIT(args, flags):
return None
-PARSER_START_RE = re.compile(r"#\s*include\s+SENF_(FIXED_)?PARSER\s*\(\s*\)")
-PARSER_END_RE = re.compile(r"SENF_PARSER_FINALIZE\s*\(([^)]*)\)\s*;")
-PARSER_FIELD_RE = re.compile(r"(?://>pkgdraw:(.*)$\s*)?SENF_PARSER_([A-Z_]+)\s*\(([^;]*)\)\s*;(?:\s*//pkgdraw:(.*)$\s*)?PKGDRAW_PARSER_([A-Z_]+)\s*\(([^;]*)\)\s*;(?:\s*@@ [...] [ -- ...]\n")
+ sys.exit(1)
+
+source = args.pop(0)
+target = args.pop(0)
+
+while args and args[0] != '--' : names.append(args.pop(0))
+if args : gccopts = args[1:]
-data = scanPackets(sys.stdin.read())
+data = scanPackets(cppExpand(quoteMacros(stripComments(file(source).read())),
+ gccopts, os.path.dirname(source)))
texf = file(os.path.join(tmpdir, "fields.tex"),"w")
texf.write(TEX_HEADER)
-if len(sys.argv) > 1:
- names = sys.argv[1:]
-else:
+if not names:
names = data.keys()
names.sort()
for name in names:
- texf.write("\\textbf{%s}\n\\bigskip\n\n" % texquote(name))
+ texf.write("\\textbf{%s}\n\\bigskip\\par\n" % texquote(name))
texf.write(PACKET_HEADER)
texf.write(makeTex(formatPacket(32, data[name])))
texf.write(PACKET_FOOTER)
@@ -318,4 +444,4 @@ if os.system("cd %s; %s/textogif -png -dpi 80 -res 0.25 fields >pkgdraw.log 2>&1
sys.stderr.write("Conversion failed. See %s\n" % tmpdir)
os._exit(1)
-sys.stdout.write(file(os.path.join(tmpdir, "fields.png")).read())
+file(target,"w").write(file(os.path.join(tmpdir, "fields.png")).read())