begin of config file parsing
Stefan Schuermans

Stefan Schuermans commited on 2017-05-25 22:18:34
Showing 7 changed files, with 223 additions and 0 deletions.

... ...
@@ -0,0 +1,3 @@
1
+*.pyc
2
+/dist/
3
+/*.egg-info
... ...
@@ -0,0 +1,4 @@
1
+from display import Display
2
+from msg import Msg, MsgDef
3
+from parse import _parse_addr, _parse_two_nos
4
+
... ...
@@ -0,0 +1,106 @@
1
+import msg
2
+import parse
3
+
4
+
5
+class Display(object):
6
+
7
+    def __init__(self, config_file, msg_obj=None):
8
+        """create a new EtherPix display
9
+           config_file: name of config file to read
10
+           msg_obj: message callback object or None"""
11
+        self._msg = msg_obj
12
+        if self._msg is None: # use default message callback if none given
13
+            self._msg = msg.MsgDef()
14
+        # default settings
15
+        self._bind_addr = ("0.0.0.0", 0) # local network address to bind to
16
+        self._size = (0, 0) # size of display
17
+        # read config file
18
+        if not self._proc_config_file(config_file):
19
+            raise Exception("error(s) while reading config file")
20
+
21
+    def _proc_config_file(self, config_file):
22
+        """process config file
23
+           config_file: name of config file to read
24
+           returns True on success, False on error"""
25
+        self._msg.msg(msg.Msg.INFO, "using config file \"%s\"" % config_file)
26
+        # process all lines in config file
27
+        okay = True
28
+        try:
29
+            with open(config_file, "r") as cfile:
30
+                lineno = 1
31
+                for line in cfile:
32
+                   if not self._proc_config_line(line, lineno):
33
+                       okay = False
34
+                   lineno += 1
35
+        except (IOError, OSError) as e:
36
+            self._msg.msg(msg.Msg.ERR, str(e))
37
+            okay = False
38
+        return okay
39
+
40
+    def _proc_config_line(self, line, lineno):
41
+        """process line from config file
42
+           line: line read from config file
43
+           lineno: line number
44
+           returns True on success, False on error"""
45
+        # parse config file line "setting = value # comment"
46
+        line_no_comment = line.split("#", 1)[0].strip()
47
+        if line_no_comment == "":
48
+            return True # ignore empty lines
49
+        else:
50
+            fields = line_no_comment.split("=", 1)
51
+            if len(fields) < 2:
52
+                self._msg.msg(msg.Msg.WARN,
53
+                              "invalid line %u in config file, ignored"
54
+                              % lineno)
55
+                return True
56
+            else:
57
+                setting = fields[0].strip()
58
+                value = fields[1].strip()
59
+                return self._proc_config_setting(setting, value, lineno)
60
+
61
+    def _proc_config_setting(self, setting, value, lineno):
62
+        """process setting from config file
63
+           setting: name of setting
64
+           value: value of setting
65
+           returns True on success, False on error"""
66
+        # replace all whitespace sequences in setting with single spaces
67
+        setting = " ".join(setting.split())
68
+        # process setting
69
+        if setting == "bindAddr":
70
+            addr = parse._parse_addr(value)
71
+            if addr is None:
72
+                self._msg.msg(msg.Msg.ERR,
73
+                              "invalid address \"%s\" for \"bindAddr\""
74
+                              " in line %u in config file"
75
+                              % (value, lineno))
76
+                return False
77
+            else:
78
+                self._bind_addr = addr
79
+                self._msg.msg(msg.Msg.INFO,
80
+                              "bind address \"%s:%u\"" % (addr[0], addr[1]))
81
+                return True
82
+        elif setting == "size":
83
+            size = parse._parse_two_nos(value)
84
+            if size is None:
85
+                self._msg.msg(msg.Msg.ERR,
86
+                              "invalid address \"%s\" for \"size\""
87
+                              " in line %u in config file"
88
+                              % (value, lineno))
89
+                return False
90
+            else:
91
+                self._size = size
92
+                return True
93
+        elif setting.startswith("distributor "):
94
+            return True # TODO
95
+        elif setting.startswith("distributorAddr "):
96
+            return True # TODO
97
+        elif setting.startswith("mapping "):
98
+            return True # TODO
99
+        elif setting.startswith("output "):
100
+            return True # TODO
101
+        else:
102
+            self._msg.msg(msg.Msg.WARN,
103
+                          "unknown setting \"%s\" in line %u in config file,"
104
+                          " ignored" % (setting, lineno))
105
+            return True
106
+
... ...
@@ -0,0 +1,18 @@
1
+#! /usr/bin/env python
2
+
3
+import sys
4
+import pyetherpix
5
+
6
+
7
+def main(argv):
8
+    if len(argv) < 2:
9
+      print >>sys.stderr, "usage: %s <config.etp>" % argv[0]
10
+      return 2
11
+    config_file = argv[1]
12
+    pyetherpix.Display(config_file)
13
+    return 0
14
+
15
+
16
+if __name__ == "__main__":
17
+  sys.exit(main(sys.argv))
18
+
... ...
@@ -0,0 +1,42 @@
1
+import sys
2
+
3
+
4
+class Msg(object):
5
+
6
+    ERR = 1
7
+    WARN = 2
8
+    INFO = 3
9
+
10
+    def __init__(self):
11
+        """interface for message callback object"""
12
+
13
+    def msg(self, level, text):
14
+        """message is delivered
15
+           level: ERR for errors, WARN for warnings, INFO for information
16
+           text: message text"""
17
+        raise NotImplementedError("Msg.msg is not implemented")
18
+
19
+
20
+class MsgDef(Msg):
21
+
22
+    def __init__(self, level=Msg.INFO):
23
+        """default message callback implementation
24
+           level: level of messages to output"""
25
+        Msg.__init__(self)
26
+        self._level = level
27
+
28
+    def msg(self, level, text):
29
+        """message is delivered
30
+           level: ERR for errors, WARN for warnings, INFO for information
31
+           text: message text"""
32
+        if level == Msg.ERR:
33
+          prefix = "error"
34
+        elif level == Msg.WARN:
35
+          prefix = "warning"
36
+        elif level == Msg.INFO:
37
+          prefix = "info"
38
+        else:
39
+          prefix = "unknown"
40
+        if level <= self._level:
41
+          print >>sys.stderr, prefix + ": " + text
42
+
... ...
@@ -0,0 +1,37 @@
1
+def _parse_addr(addr_str):
2
+    """parse an IPv4 address, e.g. \"1.2.3.4:567\",
3
+       return tuple of IP and port, e.g. ("1.2.3.4", 567), None on error"""
4
+    fields = addr_str.split(":")
5
+    if len(fields) > 2:
6
+        return None
7
+    ip = fields[0]
8
+    port = fields[1]
9
+    if len(ip.split(".")) != 4:
10
+        return None
11
+    try:
12
+        port = int(port)
13
+    except:
14
+        return None
15
+    if port < 0 or port > 65535:
16
+        return None
17
+    return (ip, port)
18
+
19
+def _parse_two_nos(txt):
20
+    """parse two comma separated decimal unsigned integers from string,
21
+       e.g. \"12,34\", return tuple of two numbers, e.g. (12, 34),
22
+       None on error"""
23
+    fields = txt.strip().split()
24
+    if len(fields) > 1:
25
+        return None
26
+    fields = fields[0].split(",")
27
+    if len(fields) != 2:
28
+        return None
29
+    try:
30
+        no1 = int(fields[0])
31
+        no2 = int(fields[1])
32
+    except:
33
+        return None
34
+    if no1 < 0 or no2 < 0:
35
+        return None
36
+    return (no1, no2)
37
+
... ...
@@ -0,0 +1,13 @@
1
+from setuptools import setup
2
+
3
+setup(name='pyetherpix',
4
+      version='0.1',
5
+      description='python implementation of EtherPix output library',
6
+      url='https://git.blinkenarea.org?p=libetherpix',
7
+      author='Stefan Schuermans',
8
+      author_email='stefan@schuermans.info',
9
+      license='LGPLv3',
10
+      packages=['pyetherpix'],
11
+      install_requires=[],
12
+      zip_safe=False)
13
+
0 14