diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ac7c707 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +__pycache__ +protocol.egg-info diff --git a/constants.py b/constants.py index 7deea62..a6a22e2 100644 --- a/constants.py +++ b/constants.py @@ -15,7 +15,7 @@ # -> E-Mail: luis.mgarc@gmail.com # # -> WWWW: http://www.luismg.com # # -> GitHub: https://github.com/luismartingarcia # -# # # +# # ################################################################################ # # # This file is part of Protocol. # @@ -52,18 +52,17 @@ ################################################################################ # Application name -APPLICATION_NAME="Protocol" +APPLICATION_NAME = "Protocol" # Current version -APPLICATION_VERSION="0.1.0" +APPLICATION_VERSION = "0.1.0" # Author -APPLICATION_AUTHOR="Luis MartinGarcia" +APPLICATION_AUTHOR = "Luis MartinGarcia" # Author E-mail -APPLICATION_AUTHOR_EMAIL="luis.mgarc@gmail.com" +APPLICATION_AUTHOR_EMAIL = "luis.mgarc@gmail.com" # Operation return codes -OP_SUCCESS = 0 # Function performed operation successfully +OP_SUCCESS = 0 # Function performed operation successfully OP_FAILURE = -1 # Error encountered while performing operation - diff --git a/protocol b/protocol index abbed87..55e03cb 100755 --- a/protocol +++ b/protocol @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python3 ################################################################################ # ____ _ _ # # | _ \ _ __ ___ | |_ ___ ___ ___ | | # @@ -60,7 +60,11 @@ import sys from datetime import date # INTERNAL IMPORTS -from constants import * +from constants import ( + APPLICATION_NAME, APPLICATION_VERSION, + APPLICATION_AUTHOR, APPLICATION_AUTHOR_EMAIL, + OP_FAILURE, OP_SUCCESS +) import specs @@ -69,8 +73,9 @@ class ProtocolException(Exception): """ This class represents exceptions raised by the Protocol class """ + def __init__(self, errmsg): - self.errmsg=errmsg + self.errmsg = errmsg def __str__(self): return str(self.errmsg) @@ -88,17 +93,33 @@ 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.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 + # unicode + self.u_top_hdr_char_start = "┌" # Character for start of the top border line + self.u_top_hdr_char_end = "┐" # Character for end of the top border line + self.u_bottom_hdr_char_start = "└" # Character for start of the bottom border line + self.u_bottom_hdr_char_end = "┘" # Character for end of the bottom border line + self.u_hdr_char_start = "├" # Character for start of the border line + self.u_hdr_char_end = "┤" # Character for end of the border line + self.u_hdr_char_fill = "─" # Fill character for border positions + self.u_hdr_char_sep = "│" # Field separator character + self.u_hdr_connector_down = '┬' + self.u_hdr_connector_up = '┴' + self.u_hdr_connector_cross = '┼' + # ASCII + 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.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_ascii = True # True: print ASCII box characters + self.do_unicode = False # False: print unicode box characters + 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): """ @@ -110,62 +131,76 @@ class Protocol(): @raise ProtocolException in case the supplied spec is not valid """ if "?" in spec: - parts=spec.split("?") - fields=parts[0] - opts=parts[1] - if spec.count("?")>1: - raise ProtocolException("FATAL: Character '?' may only be used as an option separator.") + parts = spec.split("?") + fields = parts[0] + opts = parts[1] + if spec.count("?") > 1: + raise ProtocolException( + "FATAL: Character '?' may only be used as an option separator." + ) else: - fields=spec - opts=None + fields = spec + opts = None # Parse field spec - items=fields.split(",") + 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) + bits = int(bits) + if bits <= 0: + raise ProtocolException( + "FATAL: Fields must be at least one bit long (%s)" % spec + ) 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 + ) + self.field_list.append({"text": text, "len": bits}) # Parse options if opts is not None: - opts=opts.split(",") + opts = opts.split(",") for opt in opts: try: var, value = opt.split("=") - if var.lower()=="bits": - self.bits_per_line=int(value) - if self.bits_per_line<=0: - raise ProtocolException("FATAL: Invalid value for 'bits' option (%s)" % value) - elif var.lower()=="numbers": + if var.lower() == "bits": + self.bits_per_line = int(value) + if self.bits_per_line <= 0: + raise ProtocolException( + "FATAL: Invalid value for 'bits' option (%s)" % value + ) + elif var.lower() == "numbers": if value.lower() in ["0", "n", "no", "none", "false"]: - self.do_print_top_tens=False - self.do_print_top_units=False + self.do_print_top_tens = False + self.do_print_top_units = False elif value.lower() in ["1", "y", "yes", "none", "true"]: - self.do_print_top_tens=True - self.do_print_top_units=True + self.do_print_top_tens = True + self.do_print_top_units = True else: - raise ProtocolException("FATAL: Invalid value for 'numbers' option (%s)" % value) - elif var.lower() in ["oddchar", "evenchar", "startchar", "endchar", "sepchar"]: - if len(value)>1 or len(value)<=0: - raise ProtocolException("FATAL: Invalid value for '%s' option (%s)" % (var, value)) + raise ProtocolException( + "FATAL: Invalid value for 'numbers' option (%s)" % value + ) + elif var.lower() in [ + "oddchar", "evenchar", "startchar", "endchar", "sepchar" + ]: + if len(value) > 1 or len(value) <= 0: + raise ProtocolException( + "FATAL: Invalid value for '%s' option (%s)" % (var, value) + ) else: - if var.lower()=="oddchar": - self.hdr_char_fill_odd=value - elif var.lower()=="evenchar": - self.hdr_char_fill_even=value - elif var.lower()=="startchar": - self.hdr_char_start=value - elif var.lower()=="endchar": - self.hdr_char_end=value - elif var.lower()=="sepchar": - self.hdr_char_sep=value + if var.lower() == "oddchar": + self.hdr_char_fill_odd = value + elif var.lower() == "evenchar": + self.hdr_char_fill_even = value + elif var.lower() == "startchar": + self.hdr_char_start = value + elif var.lower() == "endchar": + self.hdr_char_end = value + elif var.lower() == "sepchar": + self.hdr_char_sep = value except ProtocolException: raise except: @@ -173,7 +208,6 @@ class Protocol(): return self.field_list - def _get_top_numbers(self): """ @return a string representing the bit units and bit tens on top of the @@ -182,23 +216,22 @@ class Protocol(): The returned string is not \n terminated, but it may contain a newline character in the middle. """ - lines=["", ""] + lines = ["", ""] if self.do_print_top_tens is True: for i in range(0, self.bits_per_line): - if str(i)[-1:]=="0": - lines[0]+=" %s" % str(i)[0] + if str(i)[-1:] == "0": + lines[0] += " %s" % str(i)[0] else: - lines[0]+=" " - lines[0]+="\n" + lines[0] += " " + lines[0] += "\n" if self.do_print_top_units is True: for i in range(0, self.bits_per_line): - lines[1]+=" %s" % str(i)[-1:] - #lines[1]+="\n" + lines[1] += " %s" % str(i)[-1:] + # lines[1] += "\n" result = "".join(lines) - return result if len(result)>0 else None + return result if len(result) > 0 else None - - def _get_horizontal(self, width=None): + def _get_horizontal(self, width=None, textline=None, fields=None, bottom=False, offset=0): """ @return the horizontal border line that separates field rows. @param width controls how many field bits the line should cover. By @@ -206,23 +239,88 @@ class Protocol(): the header. """ if width is None: - width=self.bits_per_line - if width<=0: + width = self.bits_per_line + elif 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) - return a+b+c + # if above first text line then at the top + if textline == 1: + top = True + else: + top = False + + # first character of the line + if self.do_unicode: + if top is True or offset > 0: + a = "%s" % self.u_top_hdr_char_start + elif bottom is True: + if width < self.bits_per_line: + a = "%s" % self.u_hdr_char_start + else: + a = "%s" % self.u_bottom_hdr_char_start + else: + a = "%s" % self.u_hdr_char_start + else: + a = "%s" % self.hdr_char_start + + if self.do_unicode: + # create the baseline + chars = [] + for i in range(2 * (width-1)): + chars.append(self.u_hdr_char_fill) + + # look at fields to determine where up or down connections are made + start_above = set() + start_below = set() + for field in fields: + if field["start"] != 0: + if field["line"] == textline: + index = 2 * field["start"] - 1 + if index < len(chars): + chars[index] = self.u_hdr_connector_down + start_above.add(field["start"]) + # if field["line"] == textline - 1 and field["MF"] is False: + if field["line"] == textline - 1: + index = 2 * field["start"] - 1 + if index < len(chars): + chars[index] = self.u_hdr_connector_up + start_below.add(field["start"]) + + # look for cross connectors + if top is False and bottom is False: + positions = start_above.intersection(start_below) + for position in positions: + chars[2 * position - 1] = self.u_hdr_connector_cross + + b = "".join(chars) + + else: + # if ASCII, alternate +- characters between first and last + b = (self.hdr_char_fill_even+self.hdr_char_fill_odd)*(width-1) + + # last character of the line + if self.do_unicode: + if top is True: + c = "%s%s" % (self.u_hdr_char_fill, self.u_top_hdr_char_end) + elif bottom is True: + c = "%s%s" % (self.u_hdr_char_fill, self.u_bottom_hdr_char_end) + else: + # if the field ends here and the next field spans, we need a corner + # TODO + c = "%s%s" % (self.u_hdr_char_fill, self.u_hdr_char_end) + else: + c = "%s%s" % (self.hdr_char_fill_even, self.hdr_char_end) + return a+b+c def _get_separator(self, line_end=""): """ @return a string containing a protocol field separator. Returned string is a single character and matches whatever is stored in self.hdr_char_sep """ - return self.hdr_char_sep - + if self.do_unicode: + return self.u_hdr_char_sep + else: + return self.hdr_char_sep def _process_field_list(self): """ @@ -231,36 +329,43 @@ class Protocol(): protocol fields that span more than one line). This is just a helper function to make __str__()'s life easier. """ - new_fields=[] - bits_in_line=0 - i=0 + new_fields = [] + bits_in_line = 0 + i = 0 + text_line = 1 while i < len(self.field_list): # Extract all the info we need about the field - field=self.field_list[i] - field_text= field['text'] - field_len= field['len'] - field['MF']=False + field = self.field_list[i] + field_text = field['text'] + field['MF'] = False available_in_line = self.bits_per_line - bits_in_line # If we have enough space on this line to include the current field # then just keep it as it is. - if available_in_line >= field_len: + if available_in_line >= field['len']: + field['line'] = text_line + field['start'] = bits_in_line + bits_in_line += field['len'] + field['end'] = bits_in_line - 1 new_fields.append(field) - bits_in_line+=field_len - i+=1 - if bits_in_line==self.bits_per_line: - bits_in_line=0 + i += 1 + if bits_in_line == self.bits_per_line: + bits_in_line = 0 + text_line += 1 # Otherwise, split the field into two parts, one blank and one with # the actual field text else: # Case 1: We have a field that is perfectly aligned and it # has a length that is multiple of our line length - if bits_in_line==0 and field_len%self.bits_per_line==0: + if bits_in_line == 0 and field['len'] % self.bits_per_line == 0: + field['start'] = 0 + field['end'] = self.bits_per_line - 1 + field['line'] = text_line + text_line += 1 new_fields.append(field) - i+=1 - bits_in_line=0 + i += 1 # Case 2: We weren't that lucky and the field is either not # aligned or we can't print it using an exact number of full @@ -269,23 +374,31 @@ class Protocol(): # If we have more space in the current line than in the next, # then put the field text in this one - if available_in_line >= field_len-available_in_line: - new_field = {'text':field_text, 'len':available_in_line, "MF":True} + if available_in_line >= field['len']-available_in_line: + new_field = { + 'text': field_text, 'len': available_in_line, "MF": True, + 'start': bits_in_line, 'end': self.bits_per_line - 1, + 'line': text_line, + } new_fields.append(new_field) - field['text']="" - field['len']=field_len-available_in_line - field['MF']=False + field['text'] = "" + field['len'] = field['len']-available_in_line + field['MF'] = False else: - new_field = {'text':"", 'len':available_in_line, "MF":True} + new_field = { + 'text': "", 'len': available_in_line, "MF": True, + 'start': bits_in_line, 'end': self.bits_per_line - 1, + 'line': text_line, + } new_fields.append(new_field) - field['text']=field_text - field['len']=field_len-available_in_line - field['MF']=False - bits_in_line=0 + field['text'] = field_text + field['len'] = field['len']-available_in_line + field['MF'] = False + bits_in_line = 0 + text_line += 1 continue return new_fields - # Convert to string def __str__(self): """ @@ -300,54 +413,56 @@ class Protocol(): # First of all, process our field list. This does some magic to make # the algorithm work for fields that span more than one line proto_fields = self._process_field_list() - lines=[] - numbers=self._get_top_numbers() + lines = [] + numbers = self._get_top_numbers() if numbers is not None: lines.append(numbers) - lines.append(self._get_horizontal()) + textline = 1 + lines.append(self._get_horizontal(textline=textline, fields=proto_fields)) # Print all protocol fields - bits_in_line=0 - current_line="" - fields_done=0 - p=-1 + bits_in_line = 0 + current_line = "" + fields_done = 0 + p = -1 while p < len(proto_fields)-1: - p+=1 + p += 1 # Extract all the info we need about the field field = proto_fields[p] - field_text= field['text'] - field_len= field['len'] - field_mf = field['MF'] is True # Field has more fragments + field_text = field['text'] + field_len = field['len'] + field_mf = field['MF'] is True # Field has more fragments # If the field text is too long, we truncate it, and add a dot # at the end. if len(field_text) > (field_len*2)-1: - field_text=field_text[0:(field_len*2)-1] - if len(field_text)>1: - field_text=field_text[0:-1]+"." + field_text = field_text[0:(field_len*2)-1] + if len(field_text) > 1: + field_text = field_text[0:-1]+"." # If we have space for the whole field in the current line, go # ahead and add it if self.bits_per_line-bits_in_line >= field_len: # 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 bits_in_line == 0: + current_line += self._get_separator() # Add the whole field - current_line+=str.center(field_text, (field_len*2)-1) + current_line += str.center(field_text, (field_len*2)-1) # Update counters - bits_in_line+=field_len - fields_done+=1 + bits_in_line += field_len + fields_done += 1 # If this is the last character in the line, store the line - if bits_in_line==self.bits_per_line: - current_line+=self._get_separator() + if bits_in_line == self.bits_per_line: + current_line += self._get_separator() lines.append(current_line) - current_line="" - bits_in_line=0 + current_line = "" + bits_in_line = 0 + textline += 1 # When we have a fragmented field, we may need to suppress # the floor of the field, so the current line connects # with the one that follows. E.g.: @@ -360,9 +475,17 @@ class Protocol(): if proto_fields[p+1]['len'] > self.bits_per_line - field_len: # Print some +-+-+ to cover the previous field - 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._get_horizontal( + self.bits_per_line - field_len, + textline=textline, + fields=proto_fields, + bottom=True + ) + if len(line_left) == 0: + if self.do_unicode: + line_left = self.u_hdr_char_start + else: + line_left = self.hdr_char_start # Now print some empty space to cover the part that # we can join with the field below. @@ -370,66 +493,107 @@ class Protocol(): # line, then we need to print whitespace until the # end our line if proto_fields[p+1]['len'] >= self.bits_per_line: - line_center=" "* ((2*(field_len)-1)) - line_right=self.hdr_char_end + line_center = " " * ((2*(field_len)-1)) + if self.do_unicode: + line_right = self.u_hdr_char_end + else: + line_right = self.hdr_char_end # Case 2: the field in the next row is not big enough # to cover all the space we'd like to join, so we # just print whitespace to cover as much as we can else: - line_center=" "* ((2*((proto_fields[p+1]['len']-(self.bits_per_line-field_len))))-1) - line_right=self._get_horizontal(self.bits_per_line-proto_fields[p+1]['len']) + line_center = " " * ( + (2*((proto_fields[p+1]['len']-(self.bits_per_line-field_len))))-1 + ) + line_right = self._get_horizontal( + self.bits_per_line-proto_fields[p+1]['len'], + textline=textline, + fields=proto_fields, + offset=len(line_left) + len(line_center) + ) lines.append(line_left+line_center+line_right) else: - lines.append(self._get_horizontal()) + lines.append( + self._get_horizontal(textline=textline, fields=proto_fields) + ) else: - lines.append(self._get_horizontal()) - + bottom = (p == len(proto_fields) - 1) + lines.append( + self._get_horizontal(textline=textline, + fields=proto_fields, + bottom=bottom) + ) # If this is not the last character of the line but we have no # more fields to print, wrap up - elif fields_done==len(proto_fields): - current_line+=self._get_separator() + elif fields_done == len(proto_fields): + current_line += self._get_separator() lines.append(current_line) - lines.append(self._get_horizontal(bits_in_line)) + lines.append( + self._get_horizontal( + bits_in_line, + textline=textline, + fields=proto_fields, + bottom=True + ) + ) else: # Add the separator character - current_line+=self.hdr_char_sep + if self.do_unicode: + current_line += self.u_hdr_char_sep + else: + current_line += self.hdr_char_sep # We don't have enough space for the field on this line. else: # Case 1: We are at the beginning of a new line and we need to # span more than one line - if bits_in_line==0: + if bits_in_line == 0: # Case 1a: We have a multiple of the number of bits per line - if field_len%self.bits_per_line==0: + if field_len % self.bits_per_line == 0: # Compute how many lines in total we need to print for this # big field. lines_to_print = int(((field_len/self.bits_per_line)*2)-1) # We print the field text in the central line - central_line=int(lines_to_print/2) + central_line = int(lines_to_print/2) # Print all those lines for i in range(0, lines_to_print): # 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 - end_line=self.hdr_char_end + if i % 2 == 1: + if self.do_unicode: + start_line = self.u_hdr_char_start + end_line = self.u_hdr_char_end + else: + start_line = self.hdr_char_start + end_line = self.hdr_char_end else: - start_line=self.hdr_char_sep - end_line=self.hdr_char_sep + if self.do_unicode: + start_line = self.u_hdr_char_sep + end_line = self.u_hdr_char_sep + else: + start_line = self.hdr_char_sep + end_line = self.hdr_char_sep # This is the line where we need to print the field # text. if i == central_line: lines.append(start_line + str.center(field_text, (self.bits_per_line*2)-1) + end_line) + textline += 1 # This is a line we need to leave blank else: - lines.append(start_line + (" " * ((self.bits_per_line*2)-1)) + end_line) + 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()) + if i == lines_to_print-1: + if p == len(proto_fields) - 1: + bottom = True + else: + bottom = False + lines.append( + self._get_horizontal(textline=textline, fields=proto_fields, bottom=bottom) + ) # 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 @@ -439,7 +603,7 @@ class Protocol(): # something spanning lines in a weird manner assert(False) - result= "\n".join(lines) + result = "\n".join(lines) return result @@ -453,16 +617,18 @@ class Main(): """ Class constructor. Nothing fancy. """ - self.cmd_line_args=None # Copy of the user argv - self.protocols=[] # List of protocols to print out - self.bits_per_line=None # Number of bits per line to print - self.skip_numbers=None # True to avoid printing bit units and tens - self.hdr_char_start=None # Character for start of the border line - self.hdr_char_end=None # Character for end of the border line - self.hdr_char_fill_odd=None # Fill character for border odd positions - self.hdr_char_fill_even=None # Fill character for border even positions - self.hdr_char_sep=None # Field separator character + self.cmd_line_args = None # Copy of the user argv + self.protocols = [] # List of protocols to print out + self.bits_per_line = None # Number of bits per line to print + self.skip_numbers = None # True to avoid printing bit units and tens + self.hdr_char_start = None # Character for start of the border line + self.hdr_char_end = None # Character for end of the border line + self.hdr_char_fill_odd = None # Fill character for border odd positions + self.hdr_char_fill_even = None # Fill character for border even positions + self.hdr_char_sep = None # Field separator character + self.do_ascii = True # ASCII box characters + self.do_unicode = False # unicode box characters def display_help(self): """ @@ -470,7 +636,9 @@ class Main(): """ print("") print("%s v%s" % (APPLICATION_NAME, APPLICATION_VERSION)) - print("Copyright (C) %i, %s (%s)." % (max(2014, date.today().year), APPLICATION_AUTHOR, APPLICATION_AUTHOR_EMAIL)) + print("Copyright (C) 2014-%i, %s (%s)." % ( + date.today().year, APPLICATION_AUTHOR, APPLICATION_AUTHOR_EMAIL) + ) print("This software comes with ABSOLUTELY NO WARRANTY.") print("") self.display_usage() @@ -478,10 +646,12 @@ class Main(): print(" : Name of an existing protocol") print(" : Field by field specification of non-existing protocol") print("OPTIONS:") + print(" -a, --ascii : Use ASCII line characters (default)") print(" -b, --bits : Number of bits per line") print(" -f, --file : Read specs from a text file") print(" -h, --help : Displays this help information") print(" -n, --no-numbers : Do not print bit numbers on top of the header") + print(" -u, --unicode : Use Unicode box characters") print(" -V, --version : Displays current version") print(" --evenchar : Character for the even positions of horizontal table borders") print(" --oddchar : Character for the odd positions of horizontal table borders") @@ -489,21 +659,18 @@ class Main(): print(" --endchar : Character that ends horizontal table borders") print(" --sepchar : Character that separates protocol fields") - def get_usage(self): """ @return a string containing application usage information """ return "Usage: %s { or } [OPTIONS]" % self.cmd_line_args[0] - def display_usage(self): """ Prints usage information to standard output """ print(self.get_usage()) - def parse_config_file(self, filename): """ This method parses the supplied configuration file and adds any protocols to our @@ -511,33 +678,32 @@ class Main(): @return The number of protocols parsed """ - i=0 + i = 0 # Read the contents of the whole file try: - f = open(filename) - lines = f.readlines() - f.close() - except: + with open(filename) as f: + lines = f.readlines() + f.close() + except (FileNotFoundError, PermissionError, OSError): print("Error while reading file %s. Please make sure it exists and it's readable." % filename) sys.exit(1) # Parse protocol specs, line by line for line in lines: # Sanitize the line - line=line.strip() + line = line.strip() # If it starts with #, or is an empty line ignore it - if line.startswith("#") or len(line)==0: + if line.startswith("#") or len(line) == 0: continue # If we have something else, treat it as a protocol spec - proto=Protocol(line) + proto = Protocol(line) self.protocols.append(proto) - i+=1 + i += 1 return i - def parse_cmd_line_args(self, argv, is_config_file=False): """ Parses command-line arguments and stores any relevant information @@ -545,7 +711,7 @@ class Main(): """ # Store a reference to command line args for later use. - if is_config_file==False: + if is_config_file is False: self.cmd_line_args = argv # Check we have received enough command-line parameters @@ -553,74 +719,84 @@ class Main(): print(self.get_usage()) sys.exit(1) else: - skip_arg=False + skip_arg = False for i in range(1, len(argv)): # Useful for args like -c . This avoids parsing the # filename as it if was a command-line flag. - if skip_arg==True: - skip_arg=False + if skip_arg is True: + skip_arg = False continue # Spec file - if argv[i]=="-f" or argv[i]=="--file": + if argv[i] == "-f" or argv[i] == "--file": # Make sure we have an actual parameter after the flag - if (i+1)>=len(argv): + if (i+1) >= len(argv): return OP_FAILURE, "Expected parameter after %s\n%s" % (argv[i], self.get_usage()) - skip_arg=True + skip_arg = True # Parse the config file protos = self.parse_config_file(argv[i+1]) if protos <= 0: return OP_FAILURE, "No protocol specifications found in the supplied file (%s)" % argv[i+1] # Bits per line - elif argv[i]=="-b" or argv[i]=="--bits": + elif argv[i] == "-b" or argv[i] == "--bits": # Make sure we have an actual parameter after the flag - if (i+1)>=len(argv): + if (i+1) >= len(argv): return OP_FAILURE, "Expected parameter after %s\n%s" % (argv[i], self.get_usage()) - skip_arg=True + skip_arg = True # Parse the config file try: - self.bits_per_line=int(argv[i+1]) - if self.bits_per_line<=0: + self.bits_per_line = int(argv[i+1]) + if self.bits_per_line <= 0: return OP_FAILURE, "Invalid number of bits per line supplied (%s)" % argv[i+1] except: return OP_FAILURE, "Invalid number of bits per line supplied (%s)" % argv[i+1] # Avoid displaying numbers on top of the header - elif argv[i]=="-n" or argv[i]=="--no-numbers": - self.skip_numbers=True + elif argv[i] == "-n" or argv[i] == "--no-numbers": + self.skip_numbers = True + + # Use ASCII line characters + elif argv[i] == "-a" or argv[i] == "--ascii": + self.do_ascii = True + self.do_unicode = False + + # Use Unicode box characters + elif argv[i] == "-u" or argv[i] == "--unicode": + self.do_ascii = False + self.do_unicode = True # Character variations elif argv[i] in ["--oddchar", "--evenchar", "--startchar", "--endchar", "--sepchar"]: # Make sure we have an actual parameter after the flag - if (i+1)>=len(argv): + if (i+1) >= len(argv): return OP_FAILURE, "Expected parameter after %s\n%s" % (argv[i], self.get_usage()) - skip_arg=True + skip_arg = True # Make sure we got a single character, not more - if len(argv[i+1])!=1: + if len(argv[i+1]) != 1: return OP_FAILURE, "A single character is expected after %s\n%s" % (argv[i], self.get_usage()) # Now let's store whatever character spec we got - if argv[i]=="--oddchar": - self.hdr_char_fill_odd=argv[i+1] - elif argv[i]=="--evenchar": - self.hdr_char_fill_even=argv[i+1] - elif argv[i]=="--startchar": - self.hdr_char_start=argv[i+1] - elif argv[i]=="--endchar": - self.hdr_char_end=argv[i+1] - elif argv[i]=="--sepchar": - self.hdr_char_sep=argv[i+1] + if argv[i] == "--oddchar": + self.hdr_char_fill_odd = argv[i+1] + elif argv[i] == "--evenchar": + self.hdr_char_fill_even = argv[i+1] + elif argv[i] == "--startchar": + self.hdr_char_start = argv[i+1] + elif argv[i] == "--endchar": + self.hdr_char_end = argv[i+1] + elif argv[i] == "--sepchar": + self.hdr_char_sep = argv[i+1] # Display help - elif argv[i]=="-h" or argv[i]=="--help": + elif argv[i] == "-h" or argv[i] == "--help": self.display_help() sys.exit(0) # Display version - elif argv[i]=="-V" or argv[i]=="--version": + elif argv[i] == "-V" or argv[i] == "--version": print("%s v%s" % (APPLICATION_NAME, APPLICATION_VERSION)) sys.exit(0) @@ -632,7 +808,7 @@ class Main(): # Protocol name or protocol spec else: # If it contains ":" characters, we have a protocol spec - if argv[i].count(":")>0: + if argv[i].count(":") > 0: spec = argv[i] # Otherwise, the user meant to display an existing protocol else: @@ -643,17 +819,17 @@ class Main(): # we need to figure out which protocol the user meant. # If the specification is ambiguous, we will error else: - start_with_the_same=[] + 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]); + 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]) @@ -671,14 +847,12 @@ class Main(): print("ERROR: %s" % str(e)) sys.exit(1) - if len(self.protocols)==0: + if len(self.protocols) == 0: print("ERROR: Missing protocol") sys.exit(1) return OP_SUCCESS, None - - def run(self): """ This is Protocol's 'core' method: parses command line argument and prints @@ -687,7 +861,7 @@ class Main(): # Parse command-line arguments code, err = self.parse_cmd_line_args(sys.argv) - if code!=OP_SUCCESS: + if code != OP_SUCCESS: print("ERROR: %s" % err) sys.exit(1) @@ -700,24 +874,29 @@ class Main(): self.protocols[i].bits_per_line = self.bits_per_line if self.skip_numbers is not None: if self.skip_numbers is True: - self.protocols[i].do_print_top_tens=False - self.protocols[i].do_print_top_units=False + self.protocols[i].do_print_top_tens = False + self.protocols[i].do_print_top_units = False else: - self.protocols[i].do_print_top_tens=True - self.protocols[i].do_print_top_units=True + self.protocols[i].do_print_top_tens = True + self.protocols[i].do_print_top_units = True + if self.do_unicode is True: + self.protocols[i].do_unicode = True + self.protocols[i].do_ascii = False + + # override ASCII default characters, can't override unicode characters if self.hdr_char_end is not None: - self.protocols[i].hdr_char_end=self.hdr_char_end + self.protocols[i].hdr_char_end = self.hdr_char_end if self.hdr_char_start is not None: - self.protocols[i].hdr_char_start=self.hdr_char_start + self.protocols[i].hdr_char_start = self.hdr_char_start if self.hdr_char_fill_even is not None: - self.protocols[i].hdr_char_fill_even=self.hdr_char_fill_even + self.protocols[i].hdr_char_fill_even = self.hdr_char_fill_even if self.hdr_char_fill_odd is not None: - self.protocols[i].hdr_char_fill_odd=self.hdr_char_fill_odd + self.protocols[i].hdr_char_fill_odd = self.hdr_char_fill_odd if self.hdr_char_sep is not None: - self.protocols[i].hdr_char_sep=self.hdr_char_sep + self.protocols[i].hdr_char_sep = self.hdr_char_sep print(self.protocols[i]) - if len(self.protocols)>1 and i!=len(self.protocols)-1: + if len(self.protocols) > 1 and i != len(self.protocols)-1: print("") diff --git a/setup.py b/setup.py index 56e649e..714f03b 100755 --- a/setup.py +++ b/setup.py @@ -55,8 +55,11 @@ # # ################################################################################ -from distutils.core import setup, Extension -setup(name='protocol', - version='0.1', - scripts=['protocol', 'constants.py', 'specs.py'] - ) +from distutils.core import setup + +setup( + name='protocol', + version='0.1', + scripts=['protocol'], + py_modules=[] +) diff --git a/specs.py b/specs.py index d9cbfdf..07c5af8 100644 --- a/specs.py +++ b/specs.py @@ -65,7 +65,7 @@ # + Payload + # | | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -ethernet="Destination Address:48,Source Address:48,EtherType:16,Payload:128?bits=48" +ethernet = "Destination Address:48,Source Address:48,EtherType:16,Payload:128?bits=48" # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ @@ -79,7 +79,7 @@ ethernet="Destination Address:48,Source Address:48,EtherType:16,Payload:128?bits # + Payload + # | | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -dot1q="Destination Address:48,Source Address:48,TPID (0x8100):16,PCP:3,D:1,\ +dot1q = "Destination Address:48,Source Address:48,TPID (0x8100):16,PCP:3,D:1,\ VLAN ID:12,EtherType:16,Payload:96?bits=48" @@ -100,7 +100,7 @@ VLAN ID:12,EtherType:16,Payload:96?bits=48" # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | data | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -tcp="Source Port:16,Destination Port:16,Sequence Number:32,\ +tcp = "Source Port:16,Destination Port:16,Sequence Number:32,\ Acknowledgment Number:32,Offset:4,Res.:4,Flags:8,Window:16,Checksum:16,\ Urgent Pointer:16,Options:24,Padding:8" @@ -112,7 +112,7 @@ Urgent Pointer:16,Options:24,Padding:8" # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Length | Checksum | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -udp="Source Port:16,Destination Port:16,Length:16,Checksum:16" +udp = "Source Port:16,Destination Port:16,Length:16,Checksum:16" # 0 1 2 3 @@ -130,7 +130,7 @@ udp="Source Port:16,Destination Port:16,Length:16,Checksum:16" # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Options | Padding | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -ip="Version:4,IHL:4,Type of Service:8,Total Length:16,Identification:16,\ +ip = "Version:4,IHL:4,Type of Service:8,Total Length:16,Identification:16,\ Flags:3,Fragment Offset:13,Time to Live:8,Protocol:8,Header Checksum:16,\ Source Address:32,Destination Address:32,Options:24,Padding:8" @@ -155,7 +155,7 @@ Source Address:32,Destination Address:32,Options:24,Padding:8" # + + # | | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -ipv6="Version:4,Traffic Class:8,Flow Label:20,Payload Length:16,Next Header:8,\ +ipv6 = "Version:4,Traffic Class:8,Flow Label:20,Payload Length:16,Next Header:8,\ Hop Limit:8, Source Address:128, Destination Address:128" @@ -170,7 +170,7 @@ Hop Limit:8, Source Address:128, Destination Address:128" # + Message Body + # | | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -icmp="Type:8,Code:8,Checksum:16,Message Body:64" +icmp = "Type:8,Code:8,Checksum:16,Message Body:64" # ICMPv4 Destination Unreachable Message @@ -184,7 +184,7 @@ icmp="Type:8,Code:8,Checksum:16,Message Body:64" # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Internet Header + 64 bits of Original Data Datagram | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -icmp_destination="Type:8,Code:8,Checksum:16,Unused:32,Internet Header + 64 bits\ +icmp_destination = "Type:8,Code:8,Checksum:16,Unused:32,Internet Header + 64 bits\ of Original Data Datagram:64" @@ -199,7 +199,7 @@ icmp_destination="Type:8,Code:8,Checksum:16,Unused:32,Internet Header + 64 bits\ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Internet Header + 64 bits of Original Data Datagram | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -icmp_time="Type:8,Code:8,Checksum:16,Unused:32,Internet Header + 64 bits of\ +icmp_time = "Type:8,Code:8,Checksum:16,Unused:32,Internet Header + 64 bits of\ Original Data Datagram:64" @@ -214,7 +214,7 @@ icmp_time="Type:8,Code:8,Checksum:16,Unused:32,Internet Header + 64 bits of\ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Internet Header + 64 bits of Original Data Datagram | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -icmp_parameter="Type:8,Code:8,Checksum:16,Pointer:8,Unused:24,Internet Header\ +icmp_parameter = "Type:8,Code:8,Checksum:16,Pointer:8,Unused:24,Internet Header\ + 64 bits of Original Data Datagram:64" @@ -229,7 +229,7 @@ icmp_parameter="Type:8,Code:8,Checksum:16,Pointer:8,Unused:24,Internet Header\ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Internet Header + 64 bits of Original Data Datagram | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -icmp_source="Type:8,Code:8,Checksum:16,Unused:32,Internet Header + 64 bits of\ +icmp_source = "Type:8,Code:8,Checksum:16,Unused:32,Internet Header + 64 bits of\ Original Data Datagram:64" @@ -244,7 +244,7 @@ icmp_source="Type:8,Code:8,Checksum:16,Unused:32,Internet Header + 64 bits of\ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Internet Header + 64 bits of Original Data Datagram | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -icmp_redirect="Type:8,Code:8,Checksum:16,Gateway Internet Address:32,Internet\ +icmp_redirect = "Type:8,Code:8,Checksum:16,Gateway Internet Address:32,Internet\ Header + 64 bits of Original Data Datagram:64" @@ -259,7 +259,7 @@ icmp_redirect="Type:8,Code:8,Checksum:16,Gateway Internet Address:32,Internet\ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Data ... # +-+-+-+-+- -icmp_echo="Type:8,Code:8,Checksum:16,Identifier:16,Sequence Number:16,Data:64" +icmp_echo = "Type:8,Code:8,Checksum:16,Identifier:16,Sequence Number:16,Data:64" # ICMPv4 Timestamp or Timestamp Reply Message @@ -277,7 +277,7 @@ icmp_echo="Type:8,Code:8,Checksum:16,Identifier:16,Sequence Number:16,Data:64" # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Transmit Timestamp | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -icmp_timestamp="Type:8,Code:8,Checksum:16,Identifier:16,Sequence Number:16,\ +icmp_timestamp = "Type:8,Code:8,Checksum:16,Identifier:16,Sequence Number:16,\ Originate Timestamp:32,Receive Timestamp:32,Transmit Timestamp:32" @@ -290,7 +290,7 @@ Originate Timestamp:32,Receive Timestamp:32,Transmit Timestamp:32" # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Identifier | Sequence Number | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -icmp_information="Type:8,Code:8,Checksum:16,Identifier:16,Sequence Number:16" +icmp_information = "Type:8,Code:8,Checksum:16,Identifier:16,Sequence Number:16" # ICMPv6 General Format @@ -303,7 +303,7 @@ icmp_information="Type:8,Code:8,Checksum:16,Identifier:16,Sequence Number:16" # | | # + Message Body + # | | -icmpv6="Type:8,Code:8,Checksum:16,Message Body:64" +icmpv6 = "Type:8,Code:8,Checksum:16,Message Body:64" # ICMPv6 Destination Unreachable Message @@ -318,7 +318,7 @@ icmpv6="Type:8,Code:8,Checksum:16,Message Body:64" # | Invoking packet data (without exceeding minimum IPv6 MTU) | # + as possible without the ICMPv6 packet + # | exceeding the minimum IPv6 MTU [IPv6] | -icmpv6_destination="Type:8,Code:8,Checksum:16,Unused:32,Invoking packet data\ +icmpv6_destination = "Type:8,Code:8,Checksum:16,Unused:32,Invoking packet data\ (without exceeding minimum IPv6 MTU):64" @@ -334,7 +334,7 @@ icmpv6_destination="Type:8,Code:8,Checksum:16,Unused:32,Invoking packet data\ # | As much of invoking packet | # + as possible without the ICMPv6 packet + # | exceeding the minimum IPv6 MTU [IPv6] | -icmpv6_big="Type:8,Code:8,Checksum:16,MTU:32,Invoking packet data (without\ +icmpv6_big = "Type:8,Code:8,Checksum:16,MTU:32,Invoking packet data (without\ exceeding minimum IPv6 MTU):64" @@ -350,7 +350,7 @@ icmpv6_big="Type:8,Code:8,Checksum:16,MTU:32,Invoking packet data (without\ # | As much of invoking packet | # + as possible without the ICMPv6 packet + # | exceeding the minimum IPv6 MTU [IPv6] | -icmpv6_time="Type:8,Code:8,Checksum:16,Unused:32,Invoking packet data (without\ +icmpv6_time = "Type:8,Code:8,Checksum:16,Unused:32,Invoking packet data (without\ exceeding minimum IPv6 MTU):64" @@ -366,7 +366,7 @@ icmpv6_time="Type:8,Code:8,Checksum:16,Unused:32,Invoking packet data (without\ # | As much of invoking packet | # + as possible without the ICMPv6 packet + # | exceeding the minimum IPv6 MTU [IPv6] | -icmpv6_parameter="Type:8,Code:8,Checksum:16,Pointer:32,Invoking packet data\ +icmpv6_parameter = "Type:8,Code:8,Checksum:16,Pointer:32,Invoking packet data\ (without exceeding minimum IPv6 MTU):64" @@ -381,7 +381,7 @@ icmpv6_parameter="Type:8,Code:8,Checksum:16,Pointer:32,Invoking packet data\ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Data ... # +-+-+-+-+- -icmpv6_echo="Type:8,Code:8,Checksum:16,Identifier:16,Sequence Number:16,Data:64" +icmpv6_echo = "Type:8,Code:8,Checksum:16,Identifier:16,Sequence Number:16,Data:64" # ICMPv6 Router Solicitation Message Format @@ -395,7 +395,7 @@ icmpv6_echo="Type:8,Code:8,Checksum:16,Identifier:16,Sequence Number:16,Data:64" # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Options ... # +-+-+-+-+-+-+-+-+-+-+-+- -icmpv6_rsol="Type:8,Code:8,Checksum:16,Reserved:32,Options:64" +icmpv6_rsol = "Type:8,Code:8,Checksum:16,Reserved:32,Options:64" # ICMPv6 Router Advertisement Message Format @@ -413,7 +413,7 @@ icmpv6_rsol="Type:8,Code:8,Checksum:16,Reserved:32,Options:64" # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Options ... # +-+-+-+-+-+-+-+-+-+-+-+- -icmpv6_radv="Type:8,Code:8,Checksum:16,Cur Hop Limit:8,M:1,O:1,Reserved:6,\ +icmpv6_radv = "Type:8,Code:8,Checksum:16,Cur Hop Limit:8,M:1,O:1,Reserved:6,\ Router Lifetime:16,Reachable Time:32,Retransmission Timer:32,Options:64" @@ -436,7 +436,7 @@ Router Lifetime:16,Reachable Time:32,Retransmission Timer:32,Options:64" # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Options ... # +-+-+-+-+-+-+-+-+-+-+-+- -icmpv6_nsol="Type:8,Code:8,Checksum:16,Reserved:32,Target Address:128,\ +icmpv6_nsol = "Type:8,Code:8,Checksum:16,Reserved:32,Target Address:128,\ Options:64" @@ -459,7 +459,7 @@ Options:64" # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Options ... # +-+-+-+-+-+-+-+-+-+-+-+- -icmpv6_nadv="Type:8,Code:8,Checksum:16,R:1,S:1,O:1,Reserved:29,Target\ +icmpv6_nadv = "Type:8,Code:8,Checksum:16,R:1,S:1,O:1,Reserved:29,Target\ Address:128,Options:64" @@ -490,30 +490,30 @@ icmpv6_nadv="Type:8,Code:8,Checksum:16,R:1,S:1,O:1,Reserved:29,Target\ # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ # | Options ... # +-+-+-+-+-+-+-+-+-+-+-+- -icmpv6_redirect="Type:8,Code:8,Checksum:16,Reserved:32,Target Address:128,\ +icmpv6_redirect = "Type:8,Code:8,Checksum:16,Reserved:32,Target Address:128,\ Destination Address:128,Options:64" dhcp = "Opcode:8,Hardware Type: 8,HW Addr Len:8,Hop Count:8,Transaction ID:32,Number of Seconds:16,Flags:16,Client IP Addr:32,Your IP Addr: 32,Server IP Addr:32,Gateway IP Addr:32,Client Hardware Addr:128,Server Host Name:512,Boot Filename:1024" -modbus_tcp="Transaction ID:16,Protocol ID:16,Length:16,Address:8,Function Code:8,Data:64" +modbus_tcp = "Transaction ID:16,Protocol ID:16,Length:16,Address:8,Function Code:8,Data:64" -profinet_rt="Frame ID:16,User Data:80,Cycle Counter:16,Data Status:8,Transfer Status:8" +profinet_rt = "Frame ID:16,User Data:80,Cycle Counter:16,Data Status:8,Transfer Status:8" -dnp3="Start:16,Length:8,Control:8,Destination Address:16,Source Address:16,CRC:16,User Data 1:128,CRC 1:16,User Data 2:112,CRC 2:16" +dnp3 = "Start:16,Length:8,Control:8,Destination Address:16,Source Address:16,CRC:16,User Data 1:128,CRC 1:16,User Data 2:112,CRC 2:16" -tsap="Type:8,Slot:5,Rack:3?bits=16" +tsap = "Type:8,Slot:5,Rack:3?bits=16" -cotp_cr="Length:8,PDU Type:8, Destination Reference:16, Source Reference:16,Class/Options:8,Param. Code:8,Param. Length:8,Param.:88" +cotp_cr = "Length:8,PDU Type:8, Destination Reference:16, Source Reference:16,Class/Options:8,Param. Code:8,Param. Length:8,Param.:88" -cotp_dt="Length:8,PDU Type:8,Num. & LDU:8?bits=24" +cotp_dt = "Length:8,PDU Type:8,Num. & LDU:8?bits=24" -cotp_dr="Length:8,PDU Type:8, Destination Reference:16, Source Reference:16,Cause:8" +cotp_dr = "Length:8,PDU Type:8, Destination Reference:16, Source Reference:16,Cause:8" -s7_header="Protocol ID:8,ROSCTR:8,Reserved:16,Request ID:16,Parameter Length:16,Data Length:16,Error Code (only ROSCTR 3):16,Function Code:8,Item Count:8?bits=16" +s7_header = "Protocol ID:8,ROSCTR:8,Reserved:16,Request ID:16,Parameter Length:16,Data Length:16,Error Code (only ROSCTR 3):16,Function Code:8,Item Count:8?bits=16" -s7_item="Var Type:8,Var Length:8,Syntax ID:8,Transport Size:8,Length:16,DB Number:16,Area:8,Address:24" +s7_item = "Var Type:8,Var Length:8,Syntax ID:8,Transport Size:8,Length:16,DB Number:16,Area:8,Address:24" -s7_data="Return Code:8,Transport Size:8,Data Length:16" +s7_data = "Return Code:8,Transport Size:8,Data Length:16" # 0 1 # 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 @@ -534,7 +534,7 @@ s7_data="Return Code:8,Transport Size:8,Data Length:16" # * * # | | # *-------------------------------* -example="Field4:4,Field4:4,Field8:8,Field16:16,Field32:32,Field64:64?bits=16,\ +example = "Field4:4,Field4:4,Field8:8,Field16:16,Field32:32,Field64:64?bits=16,\ numbers=y,startchar=*,endchar=*,evenchar=-,oddchar=-,sepchar=|" @@ -713,7 +713,7 @@ numbers=y,startchar=*,endchar=*,evenchar=-,oddchar=-,sepchar=|" # + + # | | # +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -test="Field_1:1,Field_4:4,Field_7:7,Field_10:10,Field_13:13,Field_16:16,\ +test = "Field_1:1,Field_4:4,Field_7:7,Field_10:10,Field_13:13,Field_16:16,\ Field_19:19,Field_22:22,Field_25:25,Field_28:28,Field_31:31,Field_34:34,\ Field_37:37,Field_40:40,Field_43:43,Field_46:46,Field_49:49,Field_52:52,\ Field_55:55,Field_58:58,Field_61:61,Field_64:64,Field_67:67,Field_70:70,\ @@ -724,45 +724,45 @@ Field_124:124,Field_127:127" # Dictionary of specs -protocols={"ethernet":ethernet, - "8021q":dot1q, - "dot1q":dot1q, - "tcp":tcp, - "udp":udp, - "ip":ip, - "ipv6":ipv6, - "icmp":icmp, - "icmp-destination":icmp_destination, - "icmp-time":icmp_time, - "icmp-parameter":icmp_parameter, - "icmp-source":icmp_source, - "icmp-redirect":icmp_redirect, - "icmp-echo":icmp_echo, - "icmp-timestamp":icmp_timestamp, - "icmp-information":icmp_information, - "icmpv6":icmpv6, - "icmpv6-destination":icmpv6_destination, - "icmpv6-big":icmpv6_big, - "icmpv6-time":icmpv6_time, - "icmpv6-parameter":icmpv6_parameter, - "icmpv6-echo":icmpv6_echo, - "icmpv6-rsol":icmpv6_rsol, - "icmpv6-radv":icmpv6_radv, - "icmpv6-nsol":icmpv6_nsol, - "icmpv6-nadv":icmpv6_nadv, - "icmpv6-redirect":icmpv6_redirect, - "dhcp": dhcp, - "modbus_tcp":modbus_tcp, - "profinet_rt":profinet_rt, - "tsap":tsap, - "dnp3":dnp3, - "s7_header":s7_header, - "s7_item":s7_item, - "s7_data":s7_data, - "cotp_cr":cotp_cr, - "cotp_dt":cotp_dt, - "cotp_dr":cotp_dr, - "example":example, - "test":test - } - +protocols = { + "ethernet": ethernet, + "8021q": dot1q, + "dot1q": dot1q, + "tcp": tcp, + "udp": udp, + "ip": ip, + "ipv6": ipv6, + "icmp": icmp, + "icmp-destination": icmp_destination, + "icmp-time": icmp_time, + "icmp-parameter": icmp_parameter, + "icmp-source": icmp_source, + "icmp-redirect": icmp_redirect, + "icmp-echo": icmp_echo, + "icmp-timestamp": icmp_timestamp, + "icmp-information": icmp_information, + "icmpv6": icmpv6, + "icmpv6-destination": icmpv6_destination, + "icmpv6-big": icmpv6_big, + "icmpv6-time": icmpv6_time, + "icmpv6-parameter": icmpv6_parameter, + "icmpv6-echo": icmpv6_echo, + "icmpv6-rsol": icmpv6_rsol, + "icmpv6-radv": icmpv6_radv, + "icmpv6-nsol": icmpv6_nsol, + "icmpv6-nadv": icmpv6_nadv, + "icmpv6-redirect": icmpv6_redirect, + "dhcp": dhcp, + "modbus_tcp": modbus_tcp, + "profinet_rt": profinet_rt, + "tsap": tsap, + "dnp3": dnp3, + "s7_header": s7_header, + "s7_item": s7_item, + "s7_data": s7_data, + "cotp_cr": cotp_cr, + "cotp_dt": cotp_dt, + "cotp_dr": cotp_dr, + "example": example, + "test": test +}