from pyparsing import (Word, White, Literal, ParserElement, Regex, LineEnd,
OneOrMore, Combine, Or, Optional, Suppress, Group,
nums, alphanums, printables,
- stringEnd, pythonStyleComment, QuotedString,
+ stringEnd, pythonStyleComment,
ParseBaseException)
except ImportError:
print('pyparsing is not available')
EMPTYLINE = LineEnd()
COMMENTLINE = pythonStyleComment + EOL
INTEGER = Word(nums)
-STRING = QuotedString('"')
REAL = Combine((INTEGER + Optional('.' + Optional(INTEGER))) ^ ('.' + INTEGER))
SIGNED_REAL = Combine(Optional(Word('-+')) + REAL)
UDEV_TAG = Word(string.ascii_uppercase, alphanums + '_')
'OUI',
}
+def upperhex_word(length):
+ return Word(nums + 'ABCDEF', exact=length)
+
@lru_cache()
def hwdb_grammar():
ParserElement.setDefaultWhitespaceChars('')
for category, conn in TYPES.items())
matchline_typed = Combine(prefix + Word(printables + ' ' + '®'))
- matchline_general = Combine(Or(GENERAL_MATCHES) + ':' + Word(printables))
+ matchline_general = Combine(Or(GENERAL_MATCHES) + ':' + Word(printables + ' ' + '®'))
matchline = (matchline_typed | matchline_general) + EOL
propertyline = (White(' ', exact=1).suppress() +
- Combine(UDEV_TAG - '=' - Word(alphanums + '_=:@*.!-;, "') - Optional(pythonStyleComment)) +
+ Combine(UDEV_TAG - '=' - Optional(Word(alphanums + '_=:@*.!-;, "'))
+ - Optional(pythonStyleComment)) +
EOL)
propertycomment = White(' ', exact=1) + pythonStyleComment + EOL
dpi_setting = (Optional('*')('DEFAULT') + INTEGER('DPI') + Suppress('@') + INTEGER('HZ'))('SETTINGS*')
mount_matrix_row = SIGNED_REAL + ',' + SIGNED_REAL + ',' + SIGNED_REAL
mount_matrix = (mount_matrix_row + ';' + mount_matrix_row + ';' + mount_matrix_row)('MOUNT_MATRIX')
+ xkb_setting = Optional(Word(alphanums + '+-/@._'))
props = (('MOUSE_DPI', Group(OneOrMore(dpi_setting))),
('MOUSE_WHEEL_CLICK_ANGLE', INTEGER),
('POINTINGSTICK_CONST_ACCEL', REAL),
('ID_INPUT_JOYSTICK_INTEGRATION', Or(('internal', 'external'))),
('ID_INPUT_TOUCHPAD_INTEGRATION', Or(('internal', 'external'))),
- ('XKB_FIXED_LAYOUT', STRING),
- ('XKB_FIXED_VARIANT', STRING),
- ('XKB_FIXED_MODEL', STRING),
+ ('XKB_FIXED_LAYOUT', xkb_setting),
+ ('XKB_FIXED_VARIANT', xkb_setting),
+ ('XKB_FIXED_MODEL', xkb_setting),
('KEYBOARD_LED_NUMLOCK', Literal('0')),
('KEYBOARD_LED_CAPSLOCK', Literal('0')),
('ACCEL_MOUNT_MATRIX', mount_matrix),
return []
return [convert_properties(g) for g in parsed.GROUPS]
-def check_match_uniqueness(groups):
+def check_matches(groups):
matches = sum((group[0] for group in groups), [])
+
+ # This is a partial check. The other cases could be also done, but those
+ # two are most commonly wrong.
+ grammars = { 'usb' : 'v' + upperhex_word(4) + Optional('p' + upperhex_word(4)),
+ 'pci' : 'v' + upperhex_word(8) + Optional('d' + upperhex_word(8)),
+ }
+
+ for match in matches:
+ prefix, rest = match.split(':', maxsplit=1)
+ gr = grammars.get(prefix)
+ if gr:
+ try:
+ gr.parseString(rest)
+ except ParseBaseException as e:
+ error('Pattern {!r} is invalid: {}', rest, e)
+ continue
+
+ if not rest.endswith(':*'):
+ error("pattern {!r} does not end with ':*'", match)
+
matches.sort()
prev = None
for match in matches:
for fname in args:
groups = parse(fname)
print_summary(fname, groups)
- check_match_uniqueness(groups)
+ check_matches(groups)
check_properties(groups)
sys.exit(ERROR)