diff --git a/protocol b/protocol index 8301678..34706c0 100755 --- a/protocol +++ b/protocol @@ -56,7 +56,7 @@ ################################################################################ # STANDARD LIBRARY IMPORTS -import sys +import sys, re from datetime import date # INTERNAL IMPORTS @@ -88,17 +88,18 @@ class Protocol(): Class constructor. @param spec is the textual specification that describes the protocol. """ - self.hdr_char_start="+" # Character for start of the border line - self.hdr_char_end="+" # Character for end of the border line - self.hdr_char_fill_odd="+" # Fill character for border odd positions - self.hdr_char_fill_even="-" # Fill character for border even positions - self.hdr_char_sep="|" # Field separator character - self.bits_per_line=32 # Number of bits per line - self.base_of_top_tens=10 # Base of top numbers - self.do_print_top_tens=True # True: print top numbers for bit tens - self.do_print_top_units=True # True: print top numbers for bit units - self.field_list=[] # Header fields to be printed out - self.parse_spec(spec) # Parse the received spec and populate self.field_list + self.hdr_char_start = "+" # Character for start of the border line + self.hdr_char_end = "+" # Character for end of the border line + self.hdr_char_fill_odd = "+" # Fill character for border odd positions + self.hdr_char_fill_even = "-" # Fill character for border even positions + self.hdr_char_sep = "|" # Field separator character + self.bits_per_line = 32 # Number of bits per line + self.base_of_top_tens = 10 # Base of top numbers + self.do_print_top_tens = True # True: print top numbers for bit tens + self.do_print_top_units = True # True: print top numbers for bit units + self.do_print_line_number = 0 # >0: print line numbers on left side + self.field_list = [] # Header fields to be printed out + self.parse_spec(spec) # Parse the received spec and populate self.field_list def parse_spec(self, spec): @@ -120,19 +121,44 @@ class Protocol(): fields=spec opts=None - # Parse field spec items=fields.split(",") for item in items: try: - text, bits = item.split(":") - bits=int(bits) - if bits<=0: - raise ProtocolException("FATAL: Fields must be at least one bit long (%s)" %spec) + parts = item.split(":") + if len(parts)==1: + if item in specs.protocols: + self.parse_spec(specs.protocols[item]) + else: + start_with_the_same=[] + for spec in specs.protocols: + if spec.startswith(item): + start_with_the_same.append(spec) + if len(start_with_the_same)==1: + self.parse_spec(specs.protocols[start_with_the_same[0]]) + elif len(start_with_the_same)==0: + raise ProtocolException("FATAL: neither does supplied protocol '%s' exist nor does any known protocol start with that." % item) + else: + fail = "Ambiguous protocol specifier '%s'. Did you mean any of these?" % item + for spec in start_with_the_same: + fail += "\n %s" % spec + raise ProtocolException(fail) + else: + text = parts[0] + for item in range(1, len(parts)-1): + text += ":" + parts[item] + bits = parts[-1] + bits = bits.replace("bytes", "8").replace("qwords", "64").replace("dwords", "32").replace("words", "16").replace("double", "64").replace("floats", "32") + if re.match("^[0-9+-/\*~|&^<>()]+$", bits): + bits=eval(bits) + if bits<=0: + raise ProtocolException("FATAL: Fields must be at least one bit long (%s)" % spec) + else: + raise ProtocolException("FATAL: invalid number of bits (%s)" % bits) + self.field_list.append({"text":text, "len":bits}) except ProtocolException: raise except: - raise ProtocolException("FATAL: Invalid field_list specification (%s)" %spec) - self.field_list.append({"text":text, "len":bits}) + raise ProtocolException("FATAL: Invalid field_list specification (%s)" % spec) # Parse options if opts is not None: @@ -141,13 +167,23 @@ class Protocol(): try: var, value = opt.replace(':','=').split("=") if var.lower()=="bits": - self.bits_per_line=int(value) - if self.bits_per_line<=0: + value = value.replace("bytes", "8").replace("qwords", "64").replace("dwords", "32").replace("words", "16").replace("double", "64").replace("floats", "32") + if re.match("^[0-9+-/\*~|&^<>()]+$", value): + self.bits_per_line=eval(value) + if self.bits_per_line<=0: raise ProtocolException("FATAL: Invalid value for 'bits' option (%s)" % value) + else: + raise ProtocolException("FATAL: invalid number of bits (%s)" % value) elif var.lower()=="base": self.base_of_top_tens=int(value) if self.base_of_top_tens<=0 or self.base_of_top_tens>16: raise ProtocolException("FATAL: Invalid value for 'base' option (%s)" % value) + elif var.lower()=="rows": + self.do_print_line_number=int(value) + if self.do_print_line_number<0: + raise ProtocolException("FATAL: Invalid value for 'rows' option (%s)" % value) + if self.do_print_line_number > 0: + self.do_print_line_number += 1 elif var.lower()=="numbers": if value.lower() in ["0", "n", "no", "none", "false"]: self.do_print_top_tens=False @@ -189,17 +225,18 @@ class Protocol(): """ lines=["", ""] chars="0123456789abcdef" + lines[0]+=" "*self.do_print_line_number if self.do_print_top_tens is True: for i in range(0, self.bits_per_line): - if i%self.base_of_top_tens==0: + if i%self.base_of_top_tens == 0: lines[0]+=" %s" % chars[int(i/self.base_of_top_tens)%self.base_of_top_tens] else: lines[0]+=" " lines[0]+="\n" + lines[0]+=" "*self.do_print_line_number if self.do_print_top_units is True: for i in range(0, self.bits_per_line): lines[1]+=" %s" % chars[i%self.base_of_top_tens] - #lines[1]+="\n" result = "".join(lines) return result if len(result)>0 else None @@ -216,9 +253,9 @@ class Protocol(): if width<=0: return "" else: - a="%s" % self.hdr_char_start - b=(self.hdr_char_fill_even+self.hdr_char_fill_odd)*(width-1) - c="%s%s" % (self.hdr_char_fill_even, self.hdr_char_end) + a = "%s" % self.hdr_char_start + b = (self.hdr_char_fill_even+self.hdr_char_fill_odd)*(width-1) + c = "%s%s" % (self.hdr_char_fill_even, self.hdr_char_end) return a+b+c @@ -310,13 +347,14 @@ class Protocol(): numbers=self._get_top_numbers() if numbers is not None: lines.append(numbers) - lines.append(self._get_horizontal()) + lines.append(" "*self.do_print_line_number+self._get_horizontal()) # Print all protocol fields bits_in_line=0 current_line="" fields_done=0 p=-1 + line_number=0 while p < len(proto_fields)-1: p+=1 @@ -339,7 +377,10 @@ class Protocol(): # If this is the first thing we print on a line, add the # starting character if bits_in_line==0: - current_line+=self._get_separator() + if self.do_print_line_number: + current_line+=str(line_number).rjust(self.do_print_line_number-1)+" " + line_number+=1 + current_line+=self._get_separator() # Add the whole field current_line+=str.center(field_text, (field_len*2)-1) @@ -369,6 +410,7 @@ class Protocol(): line_left=self._get_horizontal(self.bits_per_line - field_len) if len(line_left)==0: line_left=self.hdr_char_start + line_left=" "*self.do_print_line_number+line_left # Now print some empty space to cover the part that # we can join with the field below. @@ -389,7 +431,7 @@ class Protocol(): else: lines.append(self._get_horizontal()) else: - lines.append(self._get_horizontal()) + lines.append(" "*self.do_print_line_number+self._get_horizontal()) # If this is not the last character of the line but we have no @@ -420,10 +462,11 @@ class Protocol(): # Let's figure out which character we need to use # to start and end the current line if i%2==1: - start_line=self.hdr_char_start + start_line=" "*self.do_print_line_number+self.hdr_char_start end_line=self.hdr_char_end else: - start_line=self.hdr_char_sep + start_line=str(line_number).rjust(self.do_print_line_number-1)+" "+self.hdr_char_sep + line_number+=1 end_line=self.hdr_char_sep # This is the line where we need to print the field @@ -435,7 +478,7 @@ class Protocol(): lines.append(start_line + (" " * ((self.bits_per_line*2)-1)) + end_line) # If we just added the last line, add a horizontal separator if i==lines_to_print-1: - lines.append(self._get_horizontal()) + lines.append(" "*self.do_print_line_number+self._get_horizontal()) # Case 2: We are not at the beginning of the line and we need # to print something that does not fit in the current line @@ -637,46 +680,12 @@ class Main(): # Protocol name or protocol spec else: - # If it contains ":" characters, we have a protocol spec - if argv[i].count(":")>0: - spec = argv[i] - # Otherwise, the user meant to display an existing protocol - else: - # If we got an exact match, end of story - if argv[i] in specs.protocols: - spec = specs.protocols[argv[i]] - # Otherwise, we may have received a partial match so - # we need to figure out which protocol the user meant. - # If the specification is ambiguous, we will error - else: - start_with_the_same=[] - for spec in specs.protocols: - if spec.startswith(argv[i]): - start_with_the_same.append(spec) - # If we only have one entry, it means we got some - # shortened version of the protocol name but no - # ambiguity. In that case, we will use the match. - if len(start_with_the_same)==1: - spec=specs.protocols[start_with_the_same[0]] - elif len(start_with_the_same)==0: - print("ERROR: supplied protocol '%s' does not exist." % argv[i]); - sys.exit(1) - else: - print("Ambiguous protocol specifier '%s'. Did you mean any of these?" % argv[i]) - for spec in start_with_the_same: - print(" %s" % spec) - sys.exit(1) - # Finally, based on the spec, instance an actual protocol. - # Note that if the spec is incorect, the Protocol() consutrctor - # will call sys.exit() itself, so there is no need to do - # error checking here. try: - proto = Protocol(spec) + proto = Protocol(argv[i]) self.protocols.append(proto) except ProtocolException as e: print("ERROR: %s" % str(e)) sys.exit(1) - if len(self.protocols)==0: print("ERROR: Missing protocol") sys.exit(1)