X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=doclib%2Fpkgdraw;h=010262349e0fcb74c9a697306494e8861a1da4db;hb=92f8630b75f3ef50e73c48cde58645dcd1534e27;hp=7bacd98a17da449e9cd762286e12a7d06b4e9ec6;hpb=cb01986c60bd68d43a56e1f648aecd23b43cb893;p=senf.git diff --git a/doclib/pkgdraw b/doclib/pkgdraw index 7bacd98..0102623 100755 --- a/doclib/pkgdraw +++ b/doclib/pkgdraw @@ -11,7 +11,6 @@ TEX_HEADER = r"""\documentclass{scrartcl} \usepackage[latin1]{inputenc} \usepackage[T1]{fontenc} \usepackage{ae,aecompl} -\usepackage[active]{srcltx} \usepackage{color} \usepackage{bytefield} @@ -63,7 +62,7 @@ def formatSimpleField(width, start, field): namesz = areas[i]['size'] nameix = i areas[nameix]['name'] = field['name'][:int(areas[nameix]['size'] * charsPerBit)] - if len(areas) == 2 and areas[0].get('bottom',True): + if field['name'] and len(areas) == 2 and areas[0].get('bottom',True): if areas[0].get('name','') : ix = 1 else : ix = 0 if 6 <= int(areas[ix]['size'] * charsPerBit): @@ -107,6 +106,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 +133,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: @@ -151,17 +157,43 @@ def makeTex(rows): if sides == "lrtb" : sides = "" else : sides = "[%s]" % sides if area.get('filled', False): - line.append(r"\bitbox%s{%s}{\color[gray]{0.7}\rule{\width}{\height}}" % (sides, area['size'])) + line.append(r"\bitbox%s{%s}{\color[gray]{0.93}\rule{\width}{\height}}" % (sides, area['size'])) elif area.get('skip', False): line.append(r"\skippedwords") 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 +205,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 +237,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 +257,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 +265,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,28 +282,109 @@ 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.argv[0]) + 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, order = 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: - names = data.keys() - names.sort() +if not names: + order.reverse() + names = order 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 +464,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())