Anas Nashif | ed3d7c1 | 2017-04-10 08:53:23 -0400 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 2 | # |
| 3 | # Copyright (c) 2017 Intel Corporation |
| 4 | # |
Tomasz Bursztyka | 6a9ebdc | 2018-03-07 15:17:28 +0100 | [diff] [blame] | 5 | # SPDX-License-Identifier: Apache-2.0 |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 6 | # |
| 7 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 8 | # vim: ai:ts=4:sw=4 |
| 9 | |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 10 | import sys |
| 11 | import pprint |
Manivannan Sadhasivam | 7ac767b | 2019-04-22 19:44:25 +0530 | [diff] [blame] | 12 | import re |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 13 | |
| 14 | def read_until(line, fd, end): |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 15 | out = [line] |
| 16 | while True: |
| 17 | idx = line.find(end) |
| 18 | if idx < 0: |
| 19 | line = clean_line(fd.readline(), fd) |
| 20 | out.append(line) |
| 21 | else: |
| 22 | out.append(line[idx + len(end):]) |
| 23 | return out |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 24 | |
| 25 | def remove_comment(line, fd): |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 26 | out = [] |
| 27 | while True: |
| 28 | idx = line.find('/*') |
| 29 | if idx < 0: |
| 30 | idx = line.find('//') |
| 31 | if idx < 0: |
| 32 | out.append(line) |
| 33 | else: |
| 34 | out.append(line[:idx]) |
| 35 | return ' '.join(out) |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 36 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 37 | out.append(line[:idx]) |
| 38 | line = read_until(line[idx:], fd, '*/')[-1] |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 39 | |
| 40 | def clean_line(line, fd): |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 41 | return remove_comment(line, fd).strip() |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 42 | |
| 43 | def parse_node_name(line): |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 44 | line = line[:-1] |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 45 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 46 | if '@' in line: |
| 47 | line, addr = line.split('@') |
| 48 | else: |
| 49 | addr = None |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 50 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 51 | if ':' in line: |
Erwan Gouriou | fa5d6ec | 2018-03-29 09:35:28 +0200 | [diff] [blame] | 52 | if len(line.split(':')) == 3: |
| 53 | alt_label, label, name = line.split(':') |
| 54 | else: |
| 55 | label, name = line.split(':') |
| 56 | alt_label = None |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 57 | else: |
| 58 | name = line |
| 59 | label = None |
Erwan Gouriou | fa5d6ec | 2018-03-29 09:35:28 +0200 | [diff] [blame] | 60 | alt_label = None |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 61 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 62 | if addr is None: |
Erwan Gouriou | fa5d6ec | 2018-03-29 09:35:28 +0200 | [diff] [blame] | 63 | return label, name.strip(), None, None, None |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 64 | |
Erwan Gouriou | fa5d6ec | 2018-03-29 09:35:28 +0200 | [diff] [blame] | 65 | if alt_label is None: |
| 66 | return label, name.strip(), addr, int(addr, 16), None |
| 67 | |
| 68 | return label, name.strip(), addr, int(addr, 16), alt_label |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 69 | |
| 70 | def parse_values_internal(value, start, end, separator): |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 71 | out = [] |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 72 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 73 | inside = False |
| 74 | accum = [] |
| 75 | for ch in value: |
| 76 | if not inside: |
| 77 | if ch == start: |
| 78 | inside = True |
| 79 | accum = [] |
| 80 | else: |
| 81 | if ch == end: |
| 82 | inside = False |
| 83 | out.append(''.join(accum)) |
| 84 | accum = [] |
| 85 | else: |
| 86 | accum.append(ch) |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 87 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 88 | if separator == ' ': |
| 89 | out = [v.split() for v in out] |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 90 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 91 | if len(out) == 1: |
| 92 | return parse_value(out[0]) |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 93 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 94 | return [parse_value(v) for v in out] |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 95 | |
| 96 | def parse_values(value, start, end, separator): |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 97 | out = parse_values_internal(value, start, end, separator) |
| 98 | if isinstance(out, list) and \ |
| 99 | all(isinstance(v, str) and len(v) == 1 and not v.isalpha() for v in out): |
| 100 | return bytearray(out) |
| 101 | |
| 102 | return out |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 103 | |
| 104 | def parse_value(value): |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 105 | if value == '': |
| 106 | return value |
| 107 | |
| 108 | if isinstance(value, list): |
| 109 | out = [parse_value(v) for v in value] |
| 110 | return out[0] if len(out) == 1 else out |
| 111 | |
| 112 | if value[0] == '<': |
| 113 | return parse_values(value, '<', '>', ' ') |
| 114 | if value[0] == '"': |
| 115 | return parse_values(value, '"', '"', ',') |
| 116 | if value[0] == '[': |
Peter A. Bigot | 79765b8 | 2019-07-08 06:16:33 -0500 | [diff] [blame] | 117 | return list(bytes.fromhex(value[1:value.find(']')])) |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 118 | |
| 119 | if value[0] == '&': |
| 120 | return {'ref': value[1:]} |
| 121 | |
| 122 | if value[0].isdigit(): |
| 123 | if value.startswith("0x"): |
| 124 | return int(value, 16) |
| 125 | if value[0] == '0': |
| 126 | return int(value, 8) |
Manivannan Sadhasivam | 7ac767b | 2019-04-22 19:44:25 +0530 | [diff] [blame] | 127 | # Match alpha numeric values |
| 128 | if re.match("\w", value): |
| 129 | return value |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 130 | return int(value, 10) |
| 131 | |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 132 | return value |
| 133 | |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 134 | def parse_property(property, fd): |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 135 | if '=' in property: |
| 136 | key, value = property.split('=', 1) |
| 137 | value = ' '.join(read_until(value, fd, ';')).strip() |
| 138 | if not value.endswith(';'): |
| 139 | raise SyntaxError("parse_property: missing semicolon: %s" % value) |
| 140 | return key.strip(), parse_value(value[:-1]) |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 141 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 142 | property = property.strip() |
| 143 | if not property.endswith(';'): |
| 144 | raise SyntaxError("parse_property: missing semicolon: %s" % property) |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 145 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 146 | return property[:-1].strip(), True |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 147 | |
| 148 | def build_node_name(name, addr): |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 149 | if addr is None: |
| 150 | return name |
| 151 | elif isinstance(addr, int): |
| 152 | return '%s@%x' % (name, addr) |
Kumar Gala | 46e4755 | 2017-04-12 17:16:41 -0500 | [diff] [blame] | 153 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 154 | return '%s@%s' % (name, addr.strip()) |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 155 | |
| 156 | def parse_node(line, fd): |
Erwan Gouriou | fa5d6ec | 2018-03-29 09:35:28 +0200 | [diff] [blame] | 157 | label, name, addr, numeric_addr, alt_label = parse_node_name(line) |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 158 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 159 | node = { |
| 160 | 'label': label, |
| 161 | 'type': type, |
| 162 | 'addr': numeric_addr, |
| 163 | 'children': {}, |
| 164 | 'props': {}, |
| 165 | 'name': build_node_name(name, addr) |
| 166 | } |
Erwan Gouriou | fa5d6ec | 2018-03-29 09:35:28 +0200 | [diff] [blame] | 167 | if alt_label: |
| 168 | node['alt_name'] = alt_label |
| 169 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 170 | while True: |
| 171 | line = fd.readline() |
| 172 | if not line: |
| 173 | raise SyntaxError("parse_node: Missing } while parsing node") |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 174 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 175 | line = clean_line(line, fd) |
| 176 | if not line: |
| 177 | continue |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 178 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 179 | if line == "};": |
| 180 | break |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 181 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 182 | if line.endswith('{'): |
| 183 | new_node = parse_node(line, fd) |
| 184 | node['children'][new_node['name']] = new_node |
| 185 | else: |
| 186 | key, value = parse_property(line, fd) |
| 187 | node['props'][key] = value |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 188 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 189 | return node |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 190 | |
| 191 | def parse_file(fd, ignore_dts_version=False): |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 192 | nodes = {} |
| 193 | has_v1_tag = False |
| 194 | while True: |
| 195 | line = fd.readline() |
| 196 | if not line: |
| 197 | break |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 198 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 199 | line = clean_line(line, fd) |
| 200 | if not line: |
| 201 | continue |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 202 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 203 | if line.startswith('/include/ '): |
Ulf Magnusson | 399c04c | 2019-03-19 18:47:39 +0100 | [diff] [blame] | 204 | _, filename = line.split() |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 205 | with open(filename.strip()[1:-1], "r") as new_fd: |
| 206 | nodes.update(parse_file(new_fd, True)) |
| 207 | elif line == '/dts-v1/;': |
| 208 | has_v1_tag = True |
| 209 | elif line.startswith('/memreserve/ ') and line.endswith(';'): |
Ulf Magnusson | 399c04c | 2019-03-19 18:47:39 +0100 | [diff] [blame] | 210 | _, start, end = line.split() |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 211 | start = int(start, 16) |
| 212 | end = int(end[:-1], 16) |
| 213 | label = "reserved_memory_0x%x_0x%x" % (start, end) |
| 214 | nodes[label] = { |
| 215 | 'type': 'memory', |
| 216 | 'reg': [start, end], |
| 217 | 'label': label, |
| 218 | 'addr': start, |
Ulf Magnusson | 0e8e92c | 2019-03-20 21:10:44 +0100 | [diff] [blame] | 219 | 'name': '<memreserve>' |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 220 | } |
| 221 | elif line.endswith('{'): |
| 222 | if not has_v1_tag and not ignore_dts_version: |
| 223 | raise SyntaxError("parse_file: Missing /dts-v1/ tag") |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 224 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 225 | new_node = parse_node(line, fd) |
| 226 | nodes[new_node['name']] = new_node |
| 227 | else: |
| 228 | raise SyntaxError("parse_file: Couldn't understand the line: %s" % line) |
| 229 | return nodes |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 230 | |
| 231 | def dump_refs(name, value, indent=0): |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 232 | spaces = ' ' * indent |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 233 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 234 | out = [] |
| 235 | if isinstance(value, dict) and 'ref' in value: |
| 236 | out.append('%s\"%s\" -> \"%s\";' % (spaces, name, value['ref'])) |
| 237 | elif isinstance(value, list): |
| 238 | for elem in value: |
| 239 | out.extend(dump_refs(name, elem, indent)) |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 240 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 241 | return out |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 242 | |
| 243 | def dump_all_refs(name, props, indent=0): |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 244 | out = [] |
Ulf Magnusson | 399c04c | 2019-03-19 18:47:39 +0100 | [diff] [blame] | 245 | for value in props.values(): |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 246 | out.extend(dump_refs(name, value, indent)) |
| 247 | return out |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 248 | |
| 249 | def next_subgraph(count=[0]): |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 250 | count[0] += 1 |
| 251 | return 'subgraph cluster_%d' % count[0] |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 252 | |
| 253 | def get_dot_node_name(node): |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 254 | name = node['name'] |
| 255 | return name[1:] if name[0] == '&' else name |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 256 | |
| 257 | def dump_to_dot(nodes, indent=0, start_string='digraph devicetree', name=None): |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 258 | spaces = ' ' * indent |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 259 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 260 | print("%s%s {" % (spaces, start_string)) |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 261 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 262 | if name is not None: |
| 263 | print("%slabel = \"%s\";" % (spaces, name)) |
| 264 | print("%s\"%s\";" % (spaces, name)) |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 265 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 266 | ref_list = [] |
Ulf Magnusson | 399c04c | 2019-03-19 18:47:39 +0100 | [diff] [blame] | 267 | for node in nodes.values(): |
| 268 | if node['children']: |
| 269 | refs = dump_to_dot(node['children'], indent + 1, next_subgraph(), |
| 270 | get_dot_node_name(node)) |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 271 | ref_list.extend(refs) |
| 272 | else: |
Ulf Magnusson | 399c04c | 2019-03-19 18:47:39 +0100 | [diff] [blame] | 273 | print("%s\"%s\";" % (spaces, get_dot_node_name(node))) |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 274 | |
Ulf Magnusson | 399c04c | 2019-03-19 18:47:39 +0100 | [diff] [blame] | 275 | for node in nodes.values(): |
| 276 | refs = dump_all_refs(get_dot_node_name(node), node['props'], indent) |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 277 | ref_list.extend(refs) |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 278 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 279 | if start_string.startswith("digraph"): |
| 280 | print("%s%s" % (spaces, '\n'.join(ref_list))) |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 281 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 282 | print("%s}" % spaces) |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 283 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 284 | return ref_list |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 285 | |
| 286 | def main(args): |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 287 | if len(args) == 1: |
| 288 | print('Usage: %s filename.dts' % args[0]) |
| 289 | return 1 |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 290 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 291 | if '--dot' in args: |
| 292 | formatter = dump_to_dot |
| 293 | args.remove('--dot') |
| 294 | else: |
| 295 | formatter = lambda nodes: pprint.pprint(nodes, indent=2) |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 296 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 297 | with open(args[1], "r") as fd: |
| 298 | formatter(parse_file(fd)) |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 299 | |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 300 | return 0 |
Leandro Pereira | ca42e85 | 2016-12-08 12:55:45 -0800 | [diff] [blame] | 301 | |
| 302 | if __name__ == '__main__': |
Tomasz Bursztyka | b34d156 | 2018-03-07 15:45:46 +0100 | [diff] [blame] | 303 | sys.exit(main(sys.argv)) |