Skip to content

Commit

Permalink
diskdefs: New import directive in diskdef syntax
Browse files Browse the repository at this point in the history
Use this to split the standard diskdefs.cfg into separate
sub-files by name prefix.
  • Loading branch information
keirf committed Sep 6, 2024
1 parent 623bd0f commit 509df44
Show file tree
Hide file tree
Showing 30 changed files with 1,590 additions and 1,475 deletions.
113 changes: 84 additions & 29 deletions src/greaseweazle/codec/codec.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
# This is free and unencumbered software released into the public domain.
# See the file COPYING for more details, or visit <http://unlicense.org>.

from __future__ import annotations
from typing import Dict, List, Tuple, Optional

import os.path, re
Expand Down Expand Up @@ -128,16 +129,37 @@ def default_revs(self) -> float:
return max([x.default_revs for x in self.track_map.values()])



def read_diskdef_file_lines(filename: Optional[str]) -> Tuple[List[str], str]:
if filename is None:
filename = 'diskdefs.cfg'
with importlib.resources.open_text('greaseweazle.data', filename) as f:
lines = f.readlines()
else:
with open(os.path.expanduser(filename), 'r') as f:
lines = f.readlines()
return (lines, filename)
class DiskDef_File:
def __init__(self, name: Optional[str],
parent: Optional[DiskDef_File] = None,
prefix: Optional[str] = None) -> None:
self.linenr = 0
self.parent = parent
self.prefix = prefix
self.path: Optional[str] = None
self.name: str = 'diskdefs.cfg' if name is None else name
if name is None or (self.parent and not self.parent.path):
with importlib.resources.open_text('greaseweazle.data',
self.name) as f:
self.lines = f.readlines()
else:
if self.parent:
assert self.parent.path # mypy
self.path = os.path.join(os.path.dirname(self.parent.path),
self.name)
else:
self.path = os.path.expanduser(self.name)
with open(self.path, 'r') as f:
self.lines = f.readlines()

def full_prefix(self) -> str:
s: List[str] = []
p: Optional[DiskDef_File] = self
while p is not None:
if p.prefix:
s.insert(0, p.prefix)
p = p.parent
return ''.join(s)


# Import the TrackDef subclasses
Expand Down Expand Up @@ -177,18 +199,18 @@ class ParseMode:
Disk = 1
Track = 2

def get_diskdef(
def _get_diskdef(
format_name: str,
diskdef_filename: Optional[str] = None
diskdef_file: DiskDef_File
) -> Optional[DiskDef]:

parse_mode = ParseMode.Outer
active = False
prefix = diskdef_file.full_prefix()
disk: Optional[DiskDef] = None
track: Optional[TrackDef] = None
lines, diskdef_filename = read_diskdef_file_lines(diskdef_filename)

for linenr, l in enumerate(lines, start=1):
for diskdef_file.linenr, l in enumerate(diskdef_file.lines, start=1):
try:
# Strip comments and whitespace.
match = re.match(r'\s*([^#]*)', l)
Expand All @@ -201,17 +223,30 @@ def get_diskdef(

if parse_mode == ParseMode.Outer:
disk_match = re.match(r'disk\s+([\w,.-]+)', t)
error.check(disk_match is not None, 'syntax error')
assert disk_match is not None # mypy
parse_mode = ParseMode.Disk
active = disk_match.group(1) == format_name
if active:
disk = DiskDef()
if disk_match:
parse_mode = ParseMode.Disk
active = ((prefix + disk_match.group(1)).casefold()
== format_name.casefold())
if active:
disk = DiskDef()
else:
import_match = re.match(r'import\s+([\w,.-]*)\s*"([^"]+)"',
t)
error.check(import_match is not None, 'syntax error')
assert import_match is not None # mypy
disk = _get_diskdef(format_name, DiskDef_File(
name = import_match.group(2),
prefix = import_match.group(1),
parent = diskdef_file))
if disk:
break

elif parse_mode == ParseMode.Disk:
if t == 'end':
parse_mode = ParseMode.Outer
active = False
if disk:
break
continue
tracks_match = re.match(r'tracks\s+([0-9,.*-]+)'
'\s+([\w,.-]+)', t)
Expand Down Expand Up @@ -287,24 +322,44 @@ def get_diskdef(
keyval_match.group(2))

except Exception as err:
ctxt = "%s, line %d: " % (diskdef_filename, linenr)
err.args = (ctxt + err.args[0],) + err.args[1:]
if err.args and isinstance(x := err.args[0], str):
ctxt = f'At {diskdef_file.name}, line {diskdef_file.linenr}:'
ctxt += '\n' if x.startswith('At') else ' '
err.args = (ctxt + x,) + err.args[1:]
raise

return disk

def get_diskdef(
format_name: str,
diskdef_filename: Optional[str] = None
) -> Optional[DiskDef]:
diskdef_file = DiskDef_File(name = diskdef_filename)
disk = _get_diskdef(format_name, diskdef_file)
if disk is None:
return None
disk.finalise()

return disk


def print_formats(diskdef_filename: Optional[str] = None) -> str:
columns, sep, formats = 80, 2, []
lines, _ = read_diskdef_file_lines(diskdef_filename)
for l in lines:
def get_all_formats(diskdef_file: DiskDef_File) -> List[str]:
formats = []
prefix = diskdef_file.full_prefix()
for diskdef_file.linenr, l in enumerate(diskdef_file.lines, start=1):
disk_match = re.match(r'\s*disk\s+([\w,.-]+)', l)
if disk_match:
formats.append(disk_match.group(1))
formats.append(prefix + disk_match.group(1))
import_match = re.match(r'\s*import\s+([\w,.-]*)\s*"([^"]+)"', l)
if import_match:
formats += get_all_formats(DiskDef_File(
name = import_match.group(2),
prefix = import_match.group(1),
parent = diskdef_file))
return formats

def print_formats(diskdef_filename: Optional[str] = None) -> str:
columns, sep = 80, 2
diskdef_file = DiskDef_File(name = diskdef_filename)
formats = get_all_formats(diskdef_file)
formats.sort()
return util.columnify(formats)

Expand Down
Loading

0 comments on commit 509df44

Please sign in to comment.