You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
98 lines
4.1 KiB
98 lines
4.1 KiB
#!/usr/bin/env python3
|
|
import re
|
|
import json
|
|
import hashlib
|
|
from enum import Enum, auto
|
|
from .nag_object import NagObject, NagObjectType
|
|
|
|
class ParserState(Enum):
|
|
COMMENT = auto()
|
|
DEFINE = auto()
|
|
DIRECTIVE = auto()
|
|
MULTILINE = auto()
|
|
|
|
def hash_string(string:str) -> int:
|
|
hash = hashlib.sha256()
|
|
hash.update(string.encode('utf-8'))
|
|
digest = hash.hexdigest()
|
|
return int(digest,16) * 1000000
|
|
|
|
class NagParse:
|
|
def __init__(self):
|
|
self.m_config_table: dict[int,str] = dict()
|
|
self.m_objects: list[NagObject] = list()
|
|
|
|
|
|
def __str__(self):
|
|
string = str()
|
|
for object in self.m_objects:
|
|
string += str(object) + "\n"
|
|
return string
|
|
|
|
def consume_config_files(self, config_files: list[str]) -> None:
|
|
for config_file in config_files:
|
|
self.m_config_table[hash_string(config_file)] = config_file
|
|
for object in self.parse_config(config_file):
|
|
self.m_objects.append(object)
|
|
|
|
def consume_config_list(self, config_list: list[dict] ) -> None:
|
|
for object in config_list:
|
|
nag_object = NagObject()
|
|
nag_object.from_object(object)
|
|
self.m_objects.append(nag_object)
|
|
|
|
def to_json(self):
|
|
return json.dumps([x.to_object() for x in self.m_objects])
|
|
|
|
def parse_config(self,config_file: str) -> list[NagObject]:
|
|
state = ParserState.DEFINE
|
|
objects: list[NagObject] = list()
|
|
with open(config_file, 'r') as file_handle:
|
|
line_no = 0
|
|
cur_object = NagObject(config_file=config_file)
|
|
for rawline in file_handle.readlines():
|
|
# Clean up the config
|
|
line = re.sub(r'([a-z]){', r'\1 {',rawline.strip())
|
|
#line = re.sub(r'([a-zA-Z0-9])}', r'\1\n}',line.strip())
|
|
#line = re.sub(r'([a-zA-Z0-9]) }', r'\1\n}',line.strip())
|
|
line_no += 1
|
|
# This means it is a comment, we might want to save those later on
|
|
if len(line) == 0 or re.match('^[\t ]*[#]+', line):
|
|
continue
|
|
# This means we are done parsing and should reset for new object
|
|
if re.match(r'}', line):
|
|
objects.append(cur_object)
|
|
del cur_object
|
|
state = ParserState.DEFINE
|
|
continue
|
|
#if we get here it is not a comment and not the end of an object
|
|
fragments: list[str] = re.sub(' +', ' ', line.strip()).split()
|
|
|
|
# This is a new object and we should see what type it is, and what line number it is on
|
|
if state == ParserState.DEFINE:
|
|
if fragments[0] == 'define':
|
|
cur_object = NagObject(config_file=config_file, directives=list())
|
|
cur_object.m_line_no = line_no
|
|
cur_object.m_type = NagObjectType(fragments[1])
|
|
# For the next line we should be in DIRECTIVE state
|
|
state = ParserState.DIRECTIVE
|
|
else:
|
|
print("It's fucked up man")
|
|
break
|
|
# This is the DIRECTIVE state, where we want to collect key, values and find out if we should go to multiline mode
|
|
elif state == ParserState.DIRECTIVE:
|
|
if fragments[-1][-1] == '\\':
|
|
state = ParserState.MULTILINE
|
|
if re.match('^[a-z]+', fragments[0]):
|
|
cur_object.m_directives.append(
|
|
[fragments[0], " ".join(fragments[1:])])
|
|
# This is the MULTILINE state, directives can be on many lines if the '\n' is escaped with '\'
|
|
elif state == ParserState.MULTILINE:
|
|
cur_object.m_directives[-1][1] = cur_object.m_directives[-1][1].strip('\\') + ' ' + " ".join(fragments)
|
|
if fragments[-1][-1] != '\\':
|
|
state = ParserState.DIRECTIVE
|
|
else:
|
|
print("It's fucked up man")
|
|
break
|
|
return objects
|