mirror of
https://github.com/gryf/uc1541.git
synced 2026-02-02 19:55:46 +01:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 909a42dd28 | |||
| d44c9e28fa | |||
| 0bdb6d8694 | |||
| 1346a2fcf8 |
144
uc1541
144
uc1541
@@ -43,13 +43,17 @@ script behaviour:
|
|||||||
|
|
||||||
UC1541_DEBUG - if set, uc1541 will produce log in /tmp/uc1541.log file
|
UC1541_DEBUG - if set, uc1541 will produce log in /tmp/uc1541.log file
|
||||||
|
|
||||||
UC1541_VERBOSE - of set, script will be more verbose, i.e. error messages form
|
UC1541_VERBOSE - if set, script will be more verbose, i.e. error messages form
|
||||||
c1541 program will be passed to Midnight Commander, so that user will be aware
|
c1541 program will be passed to Midnight Commander, so that user will be aware
|
||||||
of error cause if any.
|
of error cause if any.
|
||||||
|
|
||||||
UC1541_HIDE_DEL - if set, no DEL entries will be shown
|
UC1541_HIDE_DEL - if set, no DEL entries will be shown
|
||||||
|
|
||||||
Changelog:
|
Changelog:
|
||||||
|
2.7 Added support for gzipped disk images
|
||||||
|
2.6 Added mkdir and run handling (or rather lack of handling :). Minor
|
||||||
|
refactoring.
|
||||||
|
2.5 Fixed bug with filenames started with a '-' sign.
|
||||||
2.4 Fixed endless loop bug for reading directory in Python implemented
|
2.4 Fixed endless loop bug for reading directory in Python implemented
|
||||||
directory reader.
|
directory reader.
|
||||||
2.3 Re added and missing method _correct_fname used for writing files
|
2.3 Re added and missing method _correct_fname used for writing files
|
||||||
@@ -70,14 +74,15 @@ Changelog:
|
|||||||
1.0 Initial release
|
1.0 Initial release
|
||||||
|
|
||||||
Author: Roman 'gryf' Dobosz <gryf73@gmail.com>
|
Author: Roman 'gryf' Dobosz <gryf73@gmail.com>
|
||||||
Date: 2012-09-30
|
Date: 2013-11-12
|
||||||
Version: 2.4
|
Version: 2.7
|
||||||
Licence: BSD
|
Licence: BSD
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
import re
|
import re
|
||||||
import os
|
import os
|
||||||
|
import gzip
|
||||||
from subprocess import Popen, PIPE
|
from subprocess import Popen, PIPE
|
||||||
|
|
||||||
if os.getenv('UC1541_DEBUG'):
|
if os.getenv('UC1541_DEBUG'):
|
||||||
@@ -93,7 +98,7 @@ if os.getenv('UC1541_DEBUG'):
|
|||||||
else:
|
else:
|
||||||
class LOG(object):
|
class LOG(object):
|
||||||
"""
|
"""
|
||||||
Dummy logger object. does nothing.
|
Dummy logger object. Does nothing.
|
||||||
"""
|
"""
|
||||||
@classmethod
|
@classmethod
|
||||||
def debug(*args, **kwargs):
|
def debug(*args, **kwargs):
|
||||||
@@ -150,16 +155,31 @@ class D64(object):
|
|||||||
Init
|
Init
|
||||||
"""
|
"""
|
||||||
LOG.debug('image: %s', dimage)
|
LOG.debug('image: %s', dimage)
|
||||||
dimage = open(dimage, 'rb')
|
self.raw = None
|
||||||
self.raw = dimage.read()
|
|
||||||
dimage.close()
|
|
||||||
|
|
||||||
self.current_sector_data = None
|
self.current_sector_data = None
|
||||||
self.next_sector = 0
|
self.next_sector = 0
|
||||||
self.next_track = None
|
self.next_track = None
|
||||||
self._dir_contents = []
|
self._dir_contents = []
|
||||||
self._already_done = []
|
self._already_done = []
|
||||||
|
|
||||||
|
self._get_raw(dimage)
|
||||||
|
|
||||||
|
def _get_raw(self, dimage):
|
||||||
|
"""Try to get contents of the D64 image either it's gzip compressed or
|
||||||
|
not."""
|
||||||
|
fobj = gzip.open(dimage)
|
||||||
|
# Although the common approach with gzipped files is to check the
|
||||||
|
# magic number, in this case there is no guarantee that first track
|
||||||
|
# does not contain exactly the same byte sequence as the magic number.
|
||||||
|
# So the only way left is to actually try to uncompress the file.
|
||||||
|
try:
|
||||||
|
self.raw = fobj.read()
|
||||||
|
except IOError:
|
||||||
|
fobj.close()
|
||||||
|
fobj = open(dimage)
|
||||||
|
self.raw = fobj.read()
|
||||||
|
fobj.close()
|
||||||
|
|
||||||
def _map_filename(self, string):
|
def _map_filename(self, string):
|
||||||
"""
|
"""
|
||||||
Transcode filename to ASCII compatible. Replace not supported
|
Transcode filename to ASCII compatible. Replace not supported
|
||||||
@@ -175,6 +195,10 @@ class D64(object):
|
|||||||
character = D64.CHAR_MAP.get(ord(chr_), '?')
|
character = D64.CHAR_MAP.get(ord(chr_), '?')
|
||||||
filename.append(character)
|
filename.append(character)
|
||||||
|
|
||||||
|
# special cases
|
||||||
|
if filename[0] == "-":
|
||||||
|
filename[0] = "?"
|
||||||
|
|
||||||
LOG.debug("string: ``%s'' mapped to: ``%s''", string,
|
LOG.debug("string: ``%s'' mapped to: ``%s''", string,
|
||||||
"".join(filename))
|
"".join(filename))
|
||||||
return "".join(filename)
|
return "".join(filename)
|
||||||
@@ -255,7 +279,7 @@ class D64(object):
|
|||||||
Traverse through sectors and store entries in _dir_contents
|
Traverse through sectors and store entries in _dir_contents
|
||||||
"""
|
"""
|
||||||
sector = self.current_sector_data
|
sector = self.current_sector_data
|
||||||
for x in range(8):
|
for dummy in range(8):
|
||||||
entry = sector[:32]
|
entry = sector[:32]
|
||||||
ftype = ord(entry[2])
|
ftype = ord(entry[2])
|
||||||
|
|
||||||
@@ -368,6 +392,16 @@ class Uc1541(object):
|
|||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
def mkdir(self, dirname):
|
||||||
|
"""Not supported"""
|
||||||
|
self.err = "D64 format doesn't support directories"
|
||||||
|
return self._show_error()
|
||||||
|
|
||||||
|
def run(self, fname):
|
||||||
|
"""Not supported"""
|
||||||
|
self.err = "Not supported, unless you are using MC on real C64 ;)"
|
||||||
|
return self._show_error()
|
||||||
|
|
||||||
def _correct_fname(self, fname):
|
def _correct_fname(self, fname):
|
||||||
"""
|
"""
|
||||||
Return filename with mapped characters, without .prg extension.
|
Return filename with mapped characters, without .prg extension.
|
||||||
@@ -434,9 +468,13 @@ class Uc1541(object):
|
|||||||
if '/' in display_name:
|
if '/' in display_name:
|
||||||
display_name = display_name.replace('/', '|')
|
display_name = display_name.replace('/', '|')
|
||||||
|
|
||||||
# workaround for space at the beggining of the filename
|
# workaround for space and dash at the beggining of the
|
||||||
if display_name[0] == ' ':
|
# filename
|
||||||
display_name = '~' + display_name[1:]
|
char_map = {' ': '~',
|
||||||
|
'-': '_'}
|
||||||
|
display_name = "".join([char_map.get(display_name[0],
|
||||||
|
display_name[0]),
|
||||||
|
display_name[1:]])
|
||||||
|
|
||||||
if ext == 'del':
|
if ext == 'del':
|
||||||
perms = "----------"
|
perms = "----------"
|
||||||
@@ -457,9 +495,9 @@ class Uc1541(object):
|
|||||||
Pass out error output from c1541 execution
|
Pass out error output from c1541 execution
|
||||||
"""
|
"""
|
||||||
if self._verbose:
|
if self._verbose:
|
||||||
sys.exit(self.err)
|
return self.err
|
||||||
else:
|
else:
|
||||||
sys.exit(1)
|
return 1
|
||||||
|
|
||||||
def _call_command(self, cmd, src=None, dst=None):
|
def _call_command(self, cmd, src=None, dst=None):
|
||||||
"""
|
"""
|
||||||
@@ -481,16 +519,16 @@ class Uc1541(object):
|
|||||||
return not self.err
|
return not self.err
|
||||||
|
|
||||||
|
|
||||||
CALL_MAP = {'list': lambda a: Uc1541(a.ARCH).list(),
|
CALL_MAP = {'list': lambda a: Uc1541(a.arch).list(),
|
||||||
'copyin': lambda a: Uc1541(a.ARCH).copyin(a.SRC, a.DST),
|
'copyin': lambda a: Uc1541(a.arch).copyin(a.src, a.dst),
|
||||||
'copyout': lambda a: Uc1541(a.ARCH).copyout(a.SRC, a.DST),
|
'copyout': lambda a: Uc1541(a.arch).copyout(a.src, a.dst),
|
||||||
'rm': lambda a: Uc1541(a.ARCH).rm(a.DST)}
|
'mkdir': lambda a: Uc1541(a.arch).mkdir(a.dst),
|
||||||
|
'rm': lambda a: Uc1541(a.arch).rm(a.dst),
|
||||||
|
'run': lambda a: Uc1541(a.arch).run(a.dst)}
|
||||||
|
|
||||||
|
|
||||||
def parse_args():
|
def parse_args():
|
||||||
"""
|
"""Use ArgumentParser to check for script arguments and execute."""
|
||||||
Use ArgumentParser to check for script arguments and execute.
|
|
||||||
"""
|
|
||||||
parser = ArgumentParser()
|
parser = ArgumentParser()
|
||||||
subparsers = parser.add_subparsers(help='supported commands')
|
subparsers = parser.add_subparsers(help='supported commands')
|
||||||
parser_list = subparsers.add_parser('list', help="List contents of D64 "
|
parser_list = subparsers.add_parser('list', help="List contents of D64 "
|
||||||
@@ -500,67 +538,79 @@ def parse_args():
|
|||||||
parser_copyout = subparsers.add_parser('copyout', help="Copy file out of "
|
parser_copyout = subparsers.add_parser('copyout', help="Copy file out of "
|
||||||
"D64 image")
|
"D64 image")
|
||||||
parser_rm = subparsers.add_parser('rm', help="Delete file from D64 image")
|
parser_rm = subparsers.add_parser('rm', help="Delete file from D64 image")
|
||||||
|
parser_mkdir = subparsers.add_parser('mkdir', help="Create directory in "
|
||||||
|
"archive")
|
||||||
|
parser_run = subparsers.add_parser('run', help="Execute archived file")
|
||||||
|
|
||||||
parser_list.add_argument('ARCH', help="D64 Image filename")
|
parser_list.add_argument('arch', help="D64 Image filename")
|
||||||
parser_list.set_defaults(func=CALL_MAP['list'])
|
parser_list.set_defaults(func=CALL_MAP['list'])
|
||||||
|
|
||||||
parser_copyin.add_argument('ARCH', help="D64 Image filename")
|
parser_copyin.add_argument('arch', help="D64 Image filename")
|
||||||
parser_copyin.add_argument('SRC', help="Source filename")
|
parser_copyin.add_argument('src', help="Source filename")
|
||||||
parser_copyin.add_argument('DST', help="Destination filename (to be "
|
parser_copyin.add_argument('dst', help="Destination filename (to be "
|
||||||
"written into D64 image)")
|
"written into D64 image)")
|
||||||
parser_copyin.set_defaults(func=CALL_MAP['copyin'])
|
parser_copyin.set_defaults(func=CALL_MAP['copyin'])
|
||||||
|
|
||||||
parser_copyout.add_argument('ARCH', help="D64 Image filename")
|
parser_copyout.add_argument('arch', help="D64 Image filename")
|
||||||
parser_copyout.add_argument('SRC', help="Source filename (to be read from"
|
parser_copyout.add_argument('src', help="Source filename (to be read from"
|
||||||
" D64 image")
|
" D64 image")
|
||||||
parser_copyout.add_argument('DST', help="Destination filename")
|
parser_copyout.add_argument('dst', help="Destination filename")
|
||||||
parser_copyout.set_defaults(func=CALL_MAP['copyout'])
|
parser_copyout.set_defaults(func=CALL_MAP['copyout'])
|
||||||
|
|
||||||
parser_rm.add_argument('ARCH', help="D64 Image filename")
|
parser_rm.add_argument('arch', help="D64 Image filename")
|
||||||
parser_rm.add_argument('DST', help="File inside D64 image to be deleted")
|
parser_rm.add_argument('dst', help="File inside D64 image to be deleted")
|
||||||
parser_rm.set_defaults(func=CALL_MAP['rm'])
|
parser_rm.set_defaults(func=CALL_MAP['rm'])
|
||||||
|
|
||||||
|
parser_mkdir.add_argument('arch', help="archive filename")
|
||||||
|
parser_mkdir.add_argument('dst', help="Directory name inside archive to "
|
||||||
|
"be created")
|
||||||
|
parser_mkdir.set_defaults(func=CALL_MAP['mkdir'])
|
||||||
|
|
||||||
|
parser_run.add_argument('arch', help="archive filename")
|
||||||
|
parser_run.add_argument('dst', help="File to be executed")
|
||||||
|
parser_run.set_defaults(func=CALL_MAP['run'])
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
return args.func(args)
|
return args.func(args)
|
||||||
|
|
||||||
|
|
||||||
def no_parse():
|
def no_parse():
|
||||||
"""
|
"""Failsafe argument "parsing". Note, that it blindly takes positional
|
||||||
Failsafe argument "parsing". Note, that it blindly takes positional
|
|
||||||
arguments without checking them. In case of wrong arguments it will
|
arguments without checking them. In case of wrong arguments it will
|
||||||
silently exit
|
silently exit"""
|
||||||
"""
|
|
||||||
try:
|
try:
|
||||||
if sys.argv[1] not in ('list', 'copyin', 'copyout', 'rm'):
|
if sys.argv[1] not in ('list', 'copyin', 'copyout', 'rm', 'mkdir',
|
||||||
|
"run"):
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
except IndexError:
|
except IndexError:
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
|
||||||
class Arg(object):
|
class Arg(object):
|
||||||
DST = None
|
"""Mimic argparse object"""
|
||||||
SRC = None
|
dst = None
|
||||||
ARCH = None
|
src = None
|
||||||
|
arch = None
|
||||||
|
|
||||||
arg = Arg()
|
arg = Arg()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
arg.ARCH = sys.argv[2]
|
arg.arch = sys.argv[2]
|
||||||
if sys.argv[1] in ('copyin', 'copyout'):
|
if sys.argv[1] in ('copyin', 'copyout'):
|
||||||
arg.SRC = sys.argv[3]
|
arg.src = sys.argv[3]
|
||||||
arg.DST = sys.argv[4]
|
arg.dst = sys.argv[4]
|
||||||
elif sys.argv[1] == 'rm':
|
elif sys.argv[1] in ('rm', 'run', 'mkdir'):
|
||||||
arg.DST = sys.argv[3]
|
arg.dst = sys.argv[3]
|
||||||
except IndexError:
|
except IndexError:
|
||||||
sys.exit(2)
|
sys.exit(2)
|
||||||
|
|
||||||
CALL_MAP[sys.argv[1]](arg)
|
return CALL_MAP[sys.argv[1]](arg)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
LOG.debug("Script params: %s", str(sys.argv))
|
LOG.debug("Script params: %s", str(sys.argv))
|
||||||
try:
|
try:
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
parse_func = parse_args
|
PARSE_FUNC = parse_args
|
||||||
except ImportError:
|
except ImportError:
|
||||||
parse_func = no_parse
|
PARSE_FUNC = no_parse
|
||||||
|
|
||||||
parse_func()
|
sys.exit(PARSE_FUNC())
|
||||||
|
|||||||
Reference in New Issue
Block a user