Module refinery.lib.scripts.bat.util
Expand source code Browse git
from __future__ import annotations
import codecs
import re
import typing
if typing.TYPE_CHECKING:
from array import array
class batchrange:
def __init__(self, start: int, step: int, stop: int):
self.start = start
self.step = step
self.stop = stop
@property
def infinite(self) -> bool:
return self.step == 0 and self.start <= self.stop
def __len__(self):
if self.step == 0:
return 0
return max(0, (self.stop - self.start) // self.step + 1)
def __iter__(self):
index = self.start
step = self.step
stop = self.stop
if step < 0:
while index >= stop:
yield str(index)
index += step
else:
while index <= stop:
yield str(index)
index += step
def batchint(expr: str, default: int | None = None):
m = int(expr.startswith('-'))
if expr[m:m + 2] in ('0x', '0X'):
base = 16
elif expr[m:m + 1] == '0':
base = 8
else:
base = 10
try:
return int(expr, base)
except ValueError:
if default is None:
raise
return default
@typing.overload
def u16(t: str) -> memoryview:
...
@typing.overload
def u16(t: memoryview | bytes | bytearray | array) -> str:
...
def u16(t):
if isinstance(t, str):
return memoryview(codecs.encode(t, 'utf-16le')).cast('H')
else:
return codecs.decode(memoryview(t), 'utf-16le')
def unquote(token: str) -> str:
return re.sub('"(.*?)("|$)', '\\1', token)
def enquote(token: str) -> str:
if re.search('[\\x20\\t\\v&<>^|]', token):
token = '"""'.join(token.split('"'))
token = F'"{token}"'
return token.replace('%', '%%')
def uncaret(token: str, ignore_quotes: bool = False) -> tuple[bool, str]:
trailing_caret = False
if ignore_quotes:
def repl(match: re.Match[str]):
nonlocal trailing_caret
if escaped := match[1]:
return escaped
trailing_caret = True
return '^'
out = re.sub('\\^(.|$)', repl, token)
return trailing_caret, out
else:
parts = re.split('(".*?")', token)
count = len(parts)
for k in range(0, count, 2):
trailing_caret, parts[k] = uncaret(parts[k], True)
return trailing_caret, ''.join(parts)
def _findstr_class_end(pattern: str, start: int) -> int | None:
j = start + 1
if j < len(pattern) and pattern[j] == '^':
j += 1
if j < len(pattern) and pattern[j] == ']':
j += 1
while j < len(pattern):
if pattern[j] == ']':
return j
j += 1
return None
def _findstr_class(text: str) -> str:
inner = text[1:-1]
negate = ''
if inner.startswith('^'):
negate, inner = '^', inner[1:]
inner = inner.replace('\\', '\\\\').replace(']', '\\]')
return F'[{negate}{inner}]'
def findstr_to_regex(pattern: str) -> str:
"""
Translate a single findstr search expression into an equivalent Python regular
expression. The findstr dialect is limited: the only metacharacters are
`. * [..] ^ $ \\< \\>` and the backslash escape; everything else, in particular
`+ ? { } ( ) |`, is matched literally.
"""
out = []
i = 0
size = len(pattern)
prev_atom = False
while i < size:
c = pattern[i]
if c == '\\':
nxt = pattern[i + 1:i + 2]
if nxt in ('<', '>'):
out.append('\\b')
prev_atom = False
elif nxt == '':
out.append('\\\\')
prev_atom = True
elif nxt in '.*[]^$\\':
out.append(re.escape(nxt))
prev_atom = True
else:
out.append(re.escape(F'\\{nxt}'))
prev_atom = True
i += 2
continue
if c == '[' and (end := _findstr_class_end(pattern, i)) is not None:
out.append(_findstr_class(pattern[i:end + 1]))
prev_atom = True
i = end + 1
continue
if c == '.':
out.append('.')
prev_atom = True
elif c == '*' and prev_atom:
out.append('*')
prev_atom = False
elif c == '^' and i == 0:
out.append('^')
prev_atom = False
elif c == '$' and i == size - 1:
out.append('$')
prev_atom = False
else:
out.append(re.escape(c))
prev_atom = True
i += 1
return ''.join(out)
Functions
def batchint(expr, default=None)-
Expand source code Browse git
def batchint(expr: str, default: int | None = None): m = int(expr.startswith('-')) if expr[m:m + 2] in ('0x', '0X'): base = 16 elif expr[m:m + 1] == '0': base = 8 else: base = 10 try: return int(expr, base) except ValueError: if default is None: raise return default def u16(t)-
Expand source code Browse git
def u16(t): if isinstance(t, str): return memoryview(codecs.encode(t, 'utf-16le')).cast('H') else: return codecs.decode(memoryview(t), 'utf-16le') def unquote(token)-
Expand source code Browse git
def unquote(token: str) -> str: return re.sub('"(.*?)("|$)', '\\1', token) def enquote(token)-
Expand source code Browse git
def enquote(token: str) -> str: if re.search('[\\x20\\t\\v&<>^|]', token): token = '"""'.join(token.split('"')) token = F'"{token}"' return token.replace('%', '%%') def uncaret(token, ignore_quotes=False)-
Expand source code Browse git
def uncaret(token: str, ignore_quotes: bool = False) -> tuple[bool, str]: trailing_caret = False if ignore_quotes: def repl(match: re.Match[str]): nonlocal trailing_caret if escaped := match[1]: return escaped trailing_caret = True return '^' out = re.sub('\\^(.|$)', repl, token) return trailing_caret, out else: parts = re.split('(".*?")', token) count = len(parts) for k in range(0, count, 2): trailing_caret, parts[k] = uncaret(parts[k], True) return trailing_caret, ''.join(parts) def findstr_to_regex(pattern)-
Translate a single findstr search expression into an equivalent Python regular expression. The findstr dialect is limited: the only metacharacters are
. * [..] ^ $ \< \>and the backslash escape; everything else, in particular+ ? { } ( ) |, is matched literally.Expand source code Browse git
def findstr_to_regex(pattern: str) -> str: """ Translate a single findstr search expression into an equivalent Python regular expression. The findstr dialect is limited: the only metacharacters are `. * [..] ^ $ \\< \\>` and the backslash escape; everything else, in particular `+ ? { } ( ) |`, is matched literally. """ out = [] i = 0 size = len(pattern) prev_atom = False while i < size: c = pattern[i] if c == '\\': nxt = pattern[i + 1:i + 2] if nxt in ('<', '>'): out.append('\\b') prev_atom = False elif nxt == '': out.append('\\\\') prev_atom = True elif nxt in '.*[]^$\\': out.append(re.escape(nxt)) prev_atom = True else: out.append(re.escape(F'\\{nxt}')) prev_atom = True i += 2 continue if c == '[' and (end := _findstr_class_end(pattern, i)) is not None: out.append(_findstr_class(pattern[i:end + 1])) prev_atom = True i = end + 1 continue if c == '.': out.append('.') prev_atom = True elif c == '*' and prev_atom: out.append('*') prev_atom = False elif c == '^' and i == 0: out.append('^') prev_atom = False elif c == '$' and i == size - 1: out.append('$') prev_atom = False else: out.append(re.escape(c)) prev_atom = True i += 1 return ''.join(out)
Classes
class batchrange (start, step, stop)-
Expand source code Browse git
class batchrange: def __init__(self, start: int, step: int, stop: int): self.start = start self.step = step self.stop = stop @property def infinite(self) -> bool: return self.step == 0 and self.start <= self.stop def __len__(self): if self.step == 0: return 0 return max(0, (self.stop - self.start) // self.step + 1) def __iter__(self): index = self.start step = self.step stop = self.stop if step < 0: while index >= stop: yield str(index) index += step else: while index <= stop: yield str(index) index += stepInstance variables
var infinite-
Expand source code Browse git
@property def infinite(self) -> bool: return self.step == 0 and self.start <= self.stop