# -*- coding: utf-8 -*- # Copyright 2019 - 2022 Avram Lubkin, All Rights Reserved
# This Source Code Form is subject to the terms of the Mozilla Public # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/.
"""
An pure Python implementation of tparm
Based on documentation in man(5) terminfo and comparing behavior of curses.tparm """
from collections import deque import operator import re
PATTERNS = tuple((re.compile(pattern), filter_) for filter_, pattern in FILTERS)
NULL = type('Null', (int,), {})(0)
class TParm(object): # pylint: disable=useless-object-inheritance """ Class to hold tparm methods and persist variables between calls """
def __init__(self, *params, **kwargs):
self.rtn = b''
self.stack = deque()
# The spec for tparm allows c string parameters, but most implementations don't # The reference code makes a best effort to determine which parameters require strings # We'll allow them without trying to predict for param in params: ifnot isinstance(param, (int, bytes)): raise TypeError('Parameters must be integers or bytes, not %s' %
type(param).__name__)
self.params = list(params)
def __call__(self, string, *params):
self.dynamic = {} # As of ncurses 6.3, dynamic variables do not persist between calls return self.child(*params).parse(string)
def _pop_c(self, group): # pylint: disable=unused-argument """ Return pop() like %c in printf """
try:
value = self.stack.pop() except IndexError:
value = NULL
# Treat null as 0x80 if value is NULL:
value = 0x80
self.rtn += b'%c' % value
def _increment_one_two(self, group): # pylint: disable=unused-argument """
Add 1 to first two parameters
Missing parameters are treated as 0's """ for index in (0, 1): try:
self.params[index] += 1 except IndexError:
self.params.append(1)
def _binary_op(self, group): """
Perform a binary operation on the last two items on the stack
The order of evaluation is the order the items were placed on the stack """
second_val = self.stack.pop()
self.stack.append(OPERATORS[group](self.stack.pop(), second_val))
def _unary_op(self, group): """
Perform a unary operation on the last item on the stack """
self.stack.append(OPERATORS[group](self.stack.pop()))
def _push_param(self, group): """
Push a parameter onto the stack If the parameter is missing, push Null """ try:
self.stack.append(self.params[int(group) - 1]) except IndexError:
self.stack.append(NULL)
def _set_dynamic(self, group): """
Set the a dynamic variable to pop() """
self.dynamic[group] = self.stack.pop()
def _get_dynamic(self, group): """
Push the value of a dynamic variable onto the stack """
self.stack.append(self.dynamic.get(group, NULL))
def _set_static(self, group): """
Set the a static variable to pop() """
self.static[group] = self.stack.pop()
def _get_static(self, group): """
Push the value of a static variable onto the stack """
self.stack.append(self.static.get(group, NULL))
def _char_constant(self, group): """
Push an character constant onto the stack """
self.stack.append(ord(group))
def _int_constant(self, group): """
Push an integer constant onto the stack """
self.stack.append(int(group))
def _push_len(self, group): # pylint: disable=unused-argument """
Replace the last item on the stack with its length """
self.stack.append(len(self.stack.pop()))
def _cond_if(self, group): """
Recursively evaluate the body of the if statement """
self.parse(group)
def _cond_then_else(self, group): """ If the last item on the stack isTrue,
recursively evaluate then statement
Do not consume last item on stack """ if self.stack[-1]:
self.parse(group)
def _cond_then_fi(self, group): """ If the last item on the stack isTrue,
recursively evaluate then statement
Always consume last item on stack """ if self.stack.pop():
self.parse(group)
def _cond_else(self, group): """ If the last item on the stack isFalse,
recursively evaluate the both of the else statement
Always consume last item on stack """ ifnot self.stack.pop():
self.parse(group)
def _cond_fi(self, group): # pylint: disable=unused-argument """
End if statement """
def _printf(self, group): """
Subset of printf-like formatting """
# : is an escape to prevent flags from being treated as % operators, ignore # Python 2 returns as ':', Python 3 returns as 58 if group[1] in (b':', 58):
group = b'%' + group[2:]
try:
value = self.stack.pop() except IndexError:
value = NULL
# Treat null as empty string when string formatting # Python 2 returns as 's', Python 3 returns as 115 if value is NULL and group[-1] in (b's', 115):
value = b''
self.rtn += group % value
def _unmatched(self, group): # pylint: disable=unused-argument """
Escape pattern with no spec is skipped """
def _literal(self, group): """
Anything not prefaced with a known pattern spec is treated literally """
self.rtn += group
def parse(self, string): """
Parsing loop
Evaluate regex patterns in order until a pattern is matched """
ifnot isinstance(string, bytes): raise TypeError("A bytes-like object is required, not '%s'" % type(string).__name__)
index = 0
length = len(string)
while index < length: for filt, meth in PATTERNS: # pragma: no branch
match = re.match(filt, string[index:]) if match:
group = match.groups()[-1] if match.groups() else match.group(0)
getattr(self, meth)(group)
index += match.end() break
return self.rtn
def child(self, *params): """ Return a new instance with the same variables, but different parameters """ return self.__class__(*params, static=self.static, dynamic=self.dynamic)
tparm = TParm() # pylint: disable=invalid-name """Reimplementation of :py:func:`curses.tparm`"""
Messung V0.5
¤ Dauer der Verarbeitung: 0.1 Sekunden
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.