HEX
Server: nginx/1.22.0
System: Linux iZuf6jdxbygmf6cco977lcZ 5.10.84-10.4.al8.x86_64 #1 SMP Tue Apr 12 12:31:07 CST 2022 x86_64
User: root (0)
PHP: 7.4.29
Disabled: passthru,exec,system,chroot,chgrp,chown,shell_exec,proc_open,proc_get_status,ini_alter,ini_restore,dl,readlink,symlink,popepassthru,stream_socket_server,fsocket,popen
Upload Files
File: //usr/local/aegis/PythonLoaderTemp/third_party/apacheconfig/parser.py
#
# This file is part of apacheconfig software.
#
# Copyright (c) 2018-2019, Ilya Etingof <etingof@gmail.com>
# License: https://github.com/etingof/apacheconfig/LICENSE.rst
#
from __future__ import unicode_literals

import logging

import ply.yacc as yacc
import six

from apacheconfig.error import ApacheConfigError

log = logging.getLogger(__name__)


class HashCommentsParser(object):
    def p_hashcomment(self, p):
        """comment : HASHCOMMENT
        """
        p[0] = ['comment', p[1]]


class CStyleCommentsParser(object):
    def p_comment(self, p):
        """comment : HASHCOMMENT
                   | CCOMMENT
        """
        p[0] = ['comment', p[1]]


class IncludesParser(object):
    def p_include(self, p):
        """include : INCLUDE
           includeoptional : INCLUDE
        """
        # lexer returns ['<<', include, whitespace, value, '>>']
        if self._preserve_whitespace:
            p[0] = ['include'] + p[1]
        else:
            p[0] = ['include', p[1][3]]


class ApacheIncludesParser(object):
    def p_apacheinclude(self, p):
        """include : INCLUDE
                   | APACHEINCLUDE
        """
        # lexer could return ['<<', include, whitespace, value, '>>'] or
        #                    [include, whitespace, value]
        if self._preserve_whitespace:
            p[0] = ['include'] + list(p[1])
            return
        filename_index = 2
        if p[1][0] == '<<':
            filename_index = 3
        p[0] = ['include', p[1][filename_index]]

    def p_includeoptional(self, p):
        """includeoptional : APACHEINCLUDEOPTIONAL
        """
        # lexer returns [includeoptional, whitespace, value]
        if self._preserve_whitespace:
            p[0] = ['includeoptional'] + list(p[1])
        else:
            p[0] = ['includeoptional', p[1][2]]


class BaseApacheConfigParser(object):

    def __init__(self, lexer, start='config', tempdir=None, debug=False):
        self._lexer = lexer
        self.tokens = lexer.tokens  # parser needs this implicitly
        self._tempdir = tempdir
        self._debug = debug
        self._start = start
        self._preserve_whitespace = self.options.get('preservewhitespace',
                                                     False)
        self.engine = None
        self.reset()

    def reset(self):
        self.engine = yacc.yacc(
            module=self,
            start=self._start,
            outputdir=self._tempdir,
            write_tables=bool(self._tempdir),
            debug=self._debug,
            debuglog=log if self._debug else yacc.NullLogger(),
            errorlog=log if self._debug else yacc.NullLogger(),
        )

    def parse(self, text):
        self.reset()
        return self.engine.parse(text)

    # PARSING RULES
    # =============

    def p_requirednewline(self, p):
        """requirednewline : NEWLINE
        """
        p[0] = p[1]

    def p_whitespace(self, p):
        """whitespace : requirednewline
                      | WHITESPACE
        """
        p[0] = p[1]

    def p_statement(self, p):
        """statement : OPTION_AND_VALUE
                     | OPTION_AND_VALUE_NOSTRIP
        """
        p[0] = ['statement']
        if self._preserve_whitespace:
            p[0] += p[1]
        else:
            if len(p[1]) > 1:
                p[0] += [p[1][0], p[1][2]]
            else:
                p[0] += p[1]

        if self.options.get('lowercasenames'):
            p[0][1] = p[0][1].lower()

    # Note: item vs comment
    # ---------------------
    # `item` and `comment` are differentiated since there can be in-line
    # comments. Comments do not necessarily need a newline to separate it
    # from a previous item, but an item needs a newline to
    # separate it from a previous item or comment.

    def p_item(self, p):
        """item : statement
                | include
                | includeoptional
                | block
        """
        p[0] = p[1]

    def p_startitem(self, p):
        """startitem : whitespace item
                     | whitespace comment
                     | item
                     | comment
        """
        if len(p) == 3:
            if self._preserve_whitespace:
                item = p[2]
                p[0] = [item[0]] + [p[1]] + item[1:]
            else:
                p[0] = p[2]
        else:
            p[0] = p[1]

    def p_miditem(self, p):
        """miditem : requirednewline item
                   | whitespace comment
                   | comment
        """
        if len(p) == 3:
            if self._preserve_whitespace:
                item = p[2]
                p[0] = [item[0]] + [p[1]] + item[1:]
            else:
                p[0] = p[2]
        else:
            p[0] = p[1]

    def p_contents(self, p):
        """contents : contents whitespace
                    | contents miditem
                    | whitespace
                    | startitem
        """
        n = len(p)
        if n == 3:
            if isinstance(p[2], six.text_type) and p[2].isspace():
                # contents whitespace
                if self._preserve_whitespace:
                    p[0] = p[1] + [p[2]]
                else:
                    p[0] = p[1]
            else:
                # contents miditem
                p[0] = p[1] + [p[2]]
        else:
            if (not self._preserve_whitespace and
               isinstance(p[1], six.text_type) and p[1].isspace()):
                # whitespace
                # (if contents only consists of whitespace)
                p[0] = []
            else:
                # startitem
                p[0] = ['contents', p[1]]

    def p_block(self, p):
        """block : OPEN_TAG contents CLOSE_TAG
                 | OPEN_CLOSE_TAG
        """
        n = len(p)
        if n == 4:
            if isinstance(p[2], six.text_type) and p[2].isspace():
                p[2] = []
            p[0] = ['block', p[1], p[2], p[3]]
        else:
            p[0] = ['block', p[1], [], "".join(p[1])]

        if self.options.get('lowercasenames'):
            p[0][1] = tuple(x.lower() for x in p[0][1])
            p[0][3] = p[0][3].lower()

    def p_config(self, p):
        """config : config contents
                  | contents
        """
        n = len(p)
        if n == 3:
            p[0] = p[1] + [p[2]]
        elif n == 2:
            p[0] = ['config', p[1]]

    def p_error(self, p):
        raise ApacheConfigError("Parser error at '%s'" % p.value
                                if p else'Unexpected EOF')


def make_parser(**options):

    parser_class = BaseApacheConfigParser

    if options.get('ccomments', True):
        parser_class = type(str('ApacheConfigParser'),
                            (parser_class, CStyleCommentsParser),
                            {'options': options})
    else:
        parser_class = type(str('ApacheConfigParser'),
                            (parser_class, HashCommentsParser),
                            {'options': options})

    if options.get('useapacheinclude', True):
        parser_class = type(str('ApacheConfigParser'),
                            (parser_class, ApacheIncludesParser),
                            {'options': options})
    else:
        parser_class = type(str('ApacheConfigParser'),
                            (parser_class, IncludesParser),
                            {'options': options})

    return parser_class