|
24 | 24 | from path import Path
|
25 | 25 | # Platform
|
26 | 26 | from platform import system
|
| 27 | +# RE |
| 28 | +from re import compile as re_compile |
| 29 | +from re import finditer |
27 | 30 | # Sys
|
28 | 31 | import sys
|
29 | 32 | # Urllib
|
@@ -178,6 +181,89 @@ def __init__(self, infile, *args, **kwargs):
|
178 | 181 | self.merge(ConfigObj(path / GAME_NAME / name, *args, **kwargs))
|
179 | 182 |
|
180 | 183 |
|
| 184 | +class Tokenize(list): |
| 185 | + """Parses the arguments from the given string.""" |
| 186 | + |
| 187 | + _pattern = re_compile('"[^"]*"|[^ ]+') |
| 188 | + |
| 189 | + def __init__(self, string, comment_prefix=None): |
| 190 | + """Splits the arguments from the given string.""" |
| 191 | + # Initialize the list |
| 192 | + super().__init__() |
| 193 | + |
| 194 | + # Store the given string as is |
| 195 | + self.string = string |
| 196 | + |
| 197 | + # Loop through all tokens |
| 198 | + for match in finditer(self._pattern, string): |
| 199 | + |
| 200 | + # Get the current match as a string |
| 201 | + arg = match.group() |
| 202 | + |
| 203 | + # Strip end line comment |
| 204 | + if comment_prefix is not None and arg.startswith(comment_prefix): |
| 205 | + self.string = self.string[:match.start()] |
| 206 | + break |
| 207 | + |
| 208 | + # Add the current argument to the list |
| 209 | + self.append(arg.strip('"')) |
| 210 | + |
| 211 | + def __str__(self): |
| 212 | + """Returns the original string (without end-line comment).""" |
| 213 | + return self.string |
| 214 | + |
| 215 | + def __hash__(self): |
| 216 | + """Hashes the original string.""" |
| 217 | + return hash(self.string) |
| 218 | + |
| 219 | + |
| 220 | +class ConfigFile(list): |
| 221 | + """Class used to parse a configuration file.""" |
| 222 | + |
| 223 | + def __init__( |
| 224 | + self, path, encoding='utf-8', comment_prefix='//', as_strings=False): |
| 225 | + """Parses the given configuation file path. |
| 226 | +
|
| 227 | + :param Path path: |
| 228 | + The path of the file to parse. |
| 229 | + :param str encoding: |
| 230 | + The encoding to use when opening the file. |
| 231 | + :param str comment_prefix: |
| 232 | + The prefix of end line comments. |
| 233 | + :param bool as_strings: |
| 234 | + Whether the parsed lines should be stored as strings rather than |
| 235 | + argument lists. |
| 236 | + """ |
| 237 | + # If the given path doesn't exist, search for it in the cfg directory |
| 238 | + if not path.isfile(): |
| 239 | + path = CFG_PATH.joinpath(path) |
| 240 | + |
| 241 | + # If no file was found, return an empty list |
| 242 | + if not path.isfile(): |
| 243 | + return |
| 244 | + |
| 245 | + # Import this here to fix cyclic imports |
| 246 | + from translations.strings import LangStrings |
| 247 | + |
| 248 | + # Open the given file and parse its content |
| 249 | + with open(path, 'r', encoding=encoding) as f: |
| 250 | + |
| 251 | + # Loop through all lines |
| 252 | + for line in f.read().splitlines(): |
| 253 | + |
| 254 | + # Parse the argument from the current line |
| 255 | + args = Tokenize( |
| 256 | + LangStrings._replace_escaped_sequences(line), |
| 257 | + comment_prefix) |
| 258 | + |
| 259 | + # Skip empty/commented lines |
| 260 | + if not args: |
| 261 | + continue |
| 262 | + |
| 263 | + # Add the current line to the list |
| 264 | + self.append(args if not as_strings else str(args)) |
| 265 | + |
| 266 | + |
181 | 267 | # =============================================================================
|
182 | 268 | # >> FUNCTIONS
|
183 | 269 | # =============================================================================
|
|
0 commit comments