pvl.dhcp.config: make quoting context-sensitive, so that only certain items get special quoting..
--- a/pvl/dhcp/config.py Mon Mar 02 00:38:59 2015 +0200
+++ b/pvl/dhcp/config.py Mon Mar 02 01:00:48 2015 +0200
@@ -3,7 +3,18 @@
import string
# simplified model of lexer chars
-TOKEN = string.ascii_letters + string.digits + '-_.:'
+TOKEN_START = string.ascii_letters + string.digits + '-'
+TOKEN = TOKEN_START + '_'
+
+# be far more lenient when parsing
+TOKEN_EXTRA = TOKEN + ':.'
+
+UNQUOTED_CONTEXT = set((
+ ('host', ),
+ ('fixed-address', ),
+ ('next-server', ),
+ ('hardware', 'ethernet'),
+))
class DHCPConfigError(Exception):
def __init__ (self, parser, error, line=None):
@@ -47,7 +58,7 @@
lexer = shlex.shlex(line, posix=True)
lexer.commenters = '#'
- lexer.wordchars = TOKEN
+ lexer.wordchars = TOKEN_EXTRA
while True:
item = lexer.get_token()
@@ -57,7 +68,7 @@
yield item
-def quote (value):
+def quote (value, context=None):
"""
Build a single field as part of a dhcp.conf line.
@@ -70,12 +81,22 @@
>>> print quote(5)
5
>>> print quote('5')
- "5"
+ 5
+ >>> print quote('foo.bar')
+ "foo.bar"
+ >>> print quote('foo.bar', context=('host', ))
+ foo.bar
+ >>> print quote('192.0.2.1', context=('fixed-address', ))
+ 192.0.2.1
+ >>> print quote('00:11:22:33:44:55', context=('hardware', 'ethernet'))
+ 00:11:22:33:44:55
"""
if isinstance(value, int):
return str(value)
- elif all(c in TOKEN for c in value):
+ elif context in UNQUOTED_CONTEXT:
+ return str(value)
+ elif value[0] in TOKEN_START and all(c in TOKEN for c in value):
return str(value)
else:
# quoted
@@ -239,29 +260,32 @@
for block in self.parse_line(line) :
yield block
-def build_line (item, end, indent=0):
+def build_line (item, end, indent=0, context=None):
"""
Build a structured line.
- >>> print build_line(['foo'], ';')
+ >>> print build_line(('foo', ), ';')
foo;
- >>> print build_line(['host', 'foo'], ' {')
+ >>> print build_line(('host', 'foo'), ' {')
host foo {
- >>> print build_line(['foo', 'bar quux'], ';', indent=1)
+ >>> print build_line(('foo', 'bar quux'), ';', indent=1)
foo "bar quux";
"""
- return ' '*indent + ' '.join(quote(field) for field in item) + end
+ return ' '*indent + ' '.join(quote(field, context=context) for field in item) + end
def build_item (item, **opts):
"""
Build a single parameter line.
- >>> print build_item(['foo'])
+ >>> print build_item(('foo', ))
foo;
"""
- return build_line(item, end=';', **opts)
+ return build_line(item, end=';',
+ context = item[:-1],
+ **opts
+ )
def build_block (block, indent=0):
"""
--- a/pvl/dhcp/tests.py Mon Mar 02 00:38:59 2015 +0200
+++ b/pvl/dhcp/tests.py Mon Mar 02 01:00:48 2015 +0200
@@ -123,6 +123,7 @@
('include', "hosts/test.conf"),
], [
config.Block(('host', 'foo'), [
+ ('option', 'host-name', "foo.test"),
('fixed-address', '192.0.2.1'),
('hardware', 'ethernet', '00:11:22:33:44:55'),
]),
@@ -135,6 +136,7 @@
include "hosts/test.conf";
host foo {
+ option host-name "foo.test";
fixed-address 192.0.2.1;
hardware ethernet 00:11:22:33:44:55;
}