addon-sdk/source/python-lib/cuddlefish/property_parser.py

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 # This Source Code Form is subject to the terms of the Mozilla Public
michael@0 2 # License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 3 # file, You can obtain one at http://mozilla.org/MPL/2.0/.
michael@0 4
michael@0 5 import re
michael@0 6 import codecs
michael@0 7
michael@0 8 class MalformedLocaleFileError(Exception):
michael@0 9 pass
michael@0 10
michael@0 11 def parse_file(path):
michael@0 12 return parse(read_file(path), path)
michael@0 13
michael@0 14 def read_file(path):
michael@0 15 try:
michael@0 16 return codecs.open( path, "r", "utf-8" ).readlines()
michael@0 17 except UnicodeDecodeError, e:
michael@0 18 raise MalformedLocaleFileError(
michael@0 19 'Following locale file is not a valid ' +
michael@0 20 'UTF-8 file: %s\n%s"' % (path, str(e)))
michael@0 21
michael@0 22 COMMENT = re.compile(r'\s*#')
michael@0 23 EMPTY = re.compile(r'^\s+$')
michael@0 24 KEYVALUE = re.compile(r"\s*([^=:]+)(=|:)\s*(.*)")
michael@0 25
michael@0 26 def parse(lines, path=None):
michael@0 27 lines = iter(lines)
michael@0 28 lineNo = 1
michael@0 29 pairs = dict()
michael@0 30 for line in lines:
michael@0 31 if COMMENT.match(line) or EMPTY.match(line) or len(line) == 0:
michael@0 32 continue
michael@0 33 m = KEYVALUE.match(line)
michael@0 34 if not m:
michael@0 35 raise MalformedLocaleFileError(
michael@0 36 'Following locale file is not a valid .properties file: %s\n'
michael@0 37 'Line %d is incorrect:\n%s' % (path, lineNo, line))
michael@0 38
michael@0 39 # All spaces are strip. Spaces at the beginning are stripped
michael@0 40 # by the regular expression. We have to strip spaces at the end.
michael@0 41 key = m.group(1).rstrip()
michael@0 42 val = m.group(3).rstrip()
michael@0 43 val = val.encode('raw-unicode-escape').decode('raw-unicode-escape')
michael@0 44
michael@0 45 # `key` can be empty when key is only made of spaces
michael@0 46 if not key:
michael@0 47 raise MalformedLocaleFileError(
michael@0 48 'Following locale file is not a valid .properties file: %s\n'
michael@0 49 'Key is invalid on line %d is incorrect:\n%s' %
michael@0 50 (path, lineNo, line))
michael@0 51
michael@0 52 # Multiline value: keep reading lines, while lines end with backslash
michael@0 53 # and strip spaces at the beginning of lines except the last line
michael@0 54 # that doesn't end up with backslash, we strip all spaces for this one.
michael@0 55 if val.endswith("\\"):
michael@0 56 val = val[:-1]
michael@0 57 try:
michael@0 58 # remove spaces before/after and especially the \n at EOL
michael@0 59 line = lines.next().strip()
michael@0 60 while line.endswith("\\"):
michael@0 61 val += line[:-1].lstrip()
michael@0 62 line = lines.next()
michael@0 63 lineNo += 1
michael@0 64 val += line.strip()
michael@0 65 except StopIteration:
michael@0 66 raise MalformedLocaleFileError(
michael@0 67 'Following locale file is not a valid .properties file: %s\n'
michael@0 68 'Unexpected EOF in multiline sequence at line %d:\n%s' %
michael@0 69 (path, lineNo, line))
michael@0 70 # Save this new pair
michael@0 71 pairs[key] = val
michael@0 72 lineNo += 1
michael@0 73
michael@0 74 normalize_plural(path, pairs)
michael@0 75 return pairs
michael@0 76
michael@0 77 # Plural forms in properties files are defined like this:
michael@0 78 # key = other form
michael@0 79 # key[one] = one form
michael@0 80 # key[...] = ...
michael@0 81 # Parse them and merge each key into one object containing all forms:
michael@0 82 # key: {
michael@0 83 # other: "other form",
michael@0 84 # one: "one form",
michael@0 85 # ...: ...
michael@0 86 # }
michael@0 87 PLURAL_FORM = re.compile(r'^(.*)\[(zero|one|two|few|many|other)\]$')
michael@0 88 def normalize_plural(path, pairs):
michael@0 89 for key in list(pairs.keys()):
michael@0 90 m = PLURAL_FORM.match(key)
michael@0 91 if not m:
michael@0 92 continue
michael@0 93 main_key = m.group(1)
michael@0 94 plural_form = m.group(2)
michael@0 95 # Allows not specifying a generic key (i.e a key without [form])
michael@0 96 if not main_key in pairs:
michael@0 97 pairs[main_key] = {}
michael@0 98 # Ensure that we always have the [other] form
michael@0 99 if not main_key + "[other]" in pairs:
michael@0 100 raise MalformedLocaleFileError(
michael@0 101 'Following locale file is not a valid UTF-8 file: %s\n'
michael@0 102 'This plural form doesn\'t have a matching `%s[other]` form:\n'
michael@0 103 '%s\n'
michael@0 104 'You have to defined following key:\n%s'
michael@0 105 % (path, main_key, key, main_key))
michael@0 106 # convert generic form into an object if it is still a string
michael@0 107 if isinstance(pairs[main_key], unicode):
michael@0 108 pairs[main_key] = {"other": pairs[main_key]}
michael@0 109 # then, add this new plural form
michael@0 110 pairs[main_key][plural_form] = pairs[key]
michael@0 111 del pairs[key]

mercurial