use bitflags::bitflags;
use core::error::Error;
use core::ffi::CStr;
use core::fmt;
pub const CH_HLINE: u32 = 192;
pub const CH_VLINE: u32 = 221;
pub const CH_ULCORNER: u32 = 176;
pub const CH_URCORNER: u32 = 174;
pub const CH_LLCORNER: u32 = 173;
pub const CH_LRCORNER: u32 = 189;
pub const CH_TTEE: u32 = 178;
pub const CH_BTEE: u32 = 177;
pub const CH_LTEE: u32 = 171;
pub const CH_RTEE: u32 = 179;
pub const CH_CROSS: u32 = 219;
pub const CH_CURS_UP: u32 = 145;
pub const CH_CURS_DOWN: u32 = 17;
pub const CH_CURS_LEFT: u32 = 157;
pub const CH_CURS_RIGHT: u32 = 29;
pub const CH_PI: u32 = 222;
pub const CH_HOME: u32 = 19;
pub const CH_DEL: u32 = 20;
pub const CH_INS: u32 = 148;
pub const CH_ENTER: u32 = 13;
pub const CH_STOP: u32 = 3;
pub const CH_LIRA: u32 = 92;
pub const CH_ESC: u32 = 27;
pub const CH_FONT_LOWER: u32 = 14;
pub const CH_FONT_UPPER: u32 = 142;
pub const CBM_A_RO: u32 = 1;
pub const CBM_A_WO: u32 = 2;
pub const CBM_A_RW: u32 = 3;
pub const CBM_READ: u32 = 0;
pub const CBM_WRITE: u32 = 1;
pub const CBM_SEQ: u32 = 2;
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct max_align_t {
pub __clang_max_align_nonce1: ::core::ffi::c_longlong,
pub __clang_max_align_nonce2: f64,
}
#[repr(C)]
#[derive(Debug, Default, Copy, Clone)]
pub struct cbm_dirent {
pub name: [::core::ffi::c_char; 17usize],
pub size: ::core::ffi::c_uint,
pub type_: ::core::ffi::c_uchar,
pub access: ::core::ffi::c_uchar,
}
extern "C" {
pub fn cbm_k_acptr() -> ::core::ffi::c_uchar;
}
extern "C" {
pub fn cbm_k_basin() -> ::core::ffi::c_uchar;
}
extern "C" {
pub fn cbm_k_bsout(C: ::core::ffi::c_uchar);
}
extern "C" {
pub fn cbm_k_chkin(FN: ::core::ffi::c_uchar) -> ::core::ffi::c_uchar;
}
extern "C" {
pub fn cbm_k_chrin() -> ::core::ffi::c_uchar;
}
extern "C" {
pub fn cbm_k_chrout(C: ::core::ffi::c_uchar);
}
extern "C" {
pub fn cbm_k_ciout(C: ::core::ffi::c_uchar);
}
extern "C" {
pub fn cbm_k_ckout(FN: ::core::ffi::c_uchar) -> ::core::ffi::c_uchar;
}
extern "C" {
pub fn cbm_k_clall();
}
extern "C" {
pub fn cbm_k_close(FN: ::core::ffi::c_uchar);
}
extern "C" {
pub fn cbm_k_clrch();
}
extern "C" {
pub fn cbm_k_getin() -> ::core::ffi::c_uchar;
}
extern "C" {
pub fn cbm_k_iobase() -> ::core::ffi::c_uint;
}
extern "C" {
pub fn cbm_k_listen(dev: ::core::ffi::c_uchar);
}
extern "C" {
pub fn cbm_k_load(flag: ::core::ffi::c_uchar, addr: ::core::ffi::c_uint)
-> ::core::ffi::c_uint;
}
extern "C" {
pub fn cbm_k_open() -> ::core::ffi::c_uchar;
}
extern "C" {
pub fn cbm_k_readst() -> ::core::ffi::c_uchar;
}
extern "C" {
pub fn cbm_k_save(start: ::core::ffi::c_uint, end: ::core::ffi::c_uint)
-> ::core::ffi::c_uchar;
}
extern "C" {
pub fn cbm_k_scnkey();
}
extern "C" {
pub fn cbm_k_second(addr: ::core::ffi::c_uchar);
}
extern "C" {
pub fn cbm_k_setlfs(
LFN: ::core::ffi::c_uchar,
DEV: ::core::ffi::c_uchar,
SA: ::core::ffi::c_uchar,
);
}
extern "C" {
pub fn cbm_k_setnam(Name: *const ::core::ffi::c_uchar);
}
extern "C" {
pub fn cbm_k_settim(timer: ::core::ffi::c_ulong);
}
extern "C" {
pub fn cbm_k_talk(dev: ::core::ffi::c_uchar);
}
extern "C" {
pub fn cbm_k_tksa(addr: ::core::ffi::c_uchar);
}
extern "C" {
pub fn cbm_k_udtim();
}
extern "C" {
pub fn cbm_k_unlsn();
}
extern "C" {
pub fn cbm_k_untlk();
}
bitflags! {
pub struct StatusFlags: u8 {
const WRITE_TIME_OUT = 0b0000_0001; const READ_TIME_OUT = 0b0000_0010; const SHORT_BLOCK = 0b0000_0100; const LONG_BLOCK = 0b0000_1000; const READ_ERROR = 0b0001_0000; const CHECKSUM_ERROR = 0b0010_0000; const END_OF_IDENTITY = 0b0100_0000; const DEVICE_NOT_PRESENT = 0b1000_0000; }
}
#[derive(Debug)]
pub enum FileError {
TooManyFiles, FileOpen, FileNotOpen, FileNotFound, DeviceNotPresent, NotInputFile, NotOutputFile, MissingFileName, IllegalDeviceNumber, StopKeyPushed, IOError, Other(u8),
}
impl FileError {
pub const fn new(code: u8) -> Self {
match code {
1 => Self::TooManyFiles,
2 => Self::FileOpen,
3 => Self::FileNotOpen,
4 => Self::FileNotFound,
5 => Self::DeviceNotPresent,
6 => Self::NotInputFile,
7 => Self::NotOutputFile,
8 => Self::MissingFileName,
9 => Self::IllegalDeviceNumber,
10 => Self::StopKeyPushed,
11 => Self::IOError,
_ => Self::Other(code),
}
}
pub const fn value(&self) -> u8 {
match &self {
Self::TooManyFiles => 1,
Self::FileOpen => 2,
Self::FileNotOpen => 3,
Self::FileNotFound => 4,
Self::DeviceNotPresent => 5,
Self::NotInputFile => 6,
Self::NotOutputFile => 7,
Self::MissingFileName => 8,
Self::IllegalDeviceNumber => 9,
Self::StopKeyPushed => 10,
Self::IOError => 11,
Self::Other(value) => *value,
}
}
}
impl From<u8> for FileError {
fn from(error_code: u8) -> Self {
FileError::new(error_code)
}
}
impl From<&FileError> for u8 {
fn from(error: &FileError) -> Self {
error.value()
}
}
impl Error for FileError {}
impl fmt::Display for FileError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "FILE ERROR: {}", u8::from(self))
}
}
fn _cbm_load(filename: &CStr, device: u8, load_address: Option<u16>) -> u16 {
let lfn = 0u8;
let (address, secondary_address) = match load_address {
Some(address) => (address, 0u8),
None => (0, 1), };
unsafe {
cbm_k_setlfs(lfn, device, secondary_address);
cbm_k_setnam(filename.to_bytes_with_nul().as_ptr());
cbm_k_load(lfn, address) - address
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Device {
Keyboard,
Tape,
RC232,
CRT,
Printer,
Plotter,
Drive8,
Drive9,
Other(u8),
}
impl Device {
pub const fn value(&self) -> u8 {
match *self {
Device::Keyboard => 0,
Device::Tape => 1,
Device::RC232 => 2,
Device::CRT => 3,
Device::Printer => 4,
Device::Plotter => 5,
Device::Drive8 => 8,
Device::Drive9 => 9,
Device::Other(number) => number,
}
}
}
impl From<u8> for Device {
fn from(value: u8) -> Self {
Device::Other(value)
}
}
impl From<Device> for u8 {
fn from(device: Device) -> Self {
device.value()
}
}
#[derive(Debug, PartialEq, Eq)]
pub struct File {
logical_file_number: u8,
}
impl File {
pub fn open(
filename: &CStr,
device: Device,
logical_file_number: u8,
) -> Result<Self, FileError> {
unsafe {
cbm_k_setlfs(logical_file_number, device.value(), 15);
cbm_k_setnam(filename.to_bytes_with_nul().as_ptr());
}
match unsafe { cbm_k_open() } {
0 => Ok(File {
logical_file_number,
}),
_ => Err(FileError::IOError),
}
}
}
impl Drop for File {
fn drop(&mut self) {
unsafe { cbm_k_close(self.logical_file_number) };
}
}
impl genio::Read for File {
type ReadError = FileError;
fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::ReadError> {
if unsafe { cbm_k_chkin(self.logical_file_number) } != 0 {
return Err(FileError::IOError);
}
let mut bytes_read = 0;
while (bytes_read < buf.len()) && (unsafe { cbm_k_readst() } == 0) {
let byte = unsafe { cbm_k_basin() };
if (unsafe { cbm_k_readst() } & 0b10111111) == 0 {
break;
}
buf[bytes_read] = byte;
bytes_read += 1;
}
Ok(bytes_read)
}
}