Files
CLK/Analyser/Static/TandyCoCo/StaticAnalyser.cpp

125 lines
3.3 KiB
C++

//
// StaticAnalyser.cpp
// Clock Signal
//
// Created by Thomas Harte on 08/05/2026.
// Copyright © 2026 Thomas Harte. All rights reserved.
//
#include "StaticAnalyser.hpp"
#include "Storage/Tape/Parsers/TandyCoCo.hpp"
#include "Storage/Disk/Parsers/TandyCoCo.hpp"
#include "Target.hpp"
Analyser::Static::TargetList Analyser::Static::TandyCoCo::GetTargets(
const Media &media,
const std::string &,
TargetPlatform::IntType,
bool
) {
TargetList targets;
auto target = std::make_unique<Target>();
target->media = media;
if(!media.tapes.empty()) {
using namespace Storage::Tape::TandyCoCo;
Parser parser;
auto &tape = media.tapes.front();
const auto serialiser = tape->serialiser();
while(!serialiser->is_at_end()) {
const auto block = parser.block(*serialiser);
if(!block.has_value()) continue;
if(!block->type && block->data.size() >= 9) {
if(!block->data[8]) {
target->loading_command = L"CLOAD:RUN\n";
} else {
target->loading_command = L"CLOADM:EXEC\n";
}
break;
}
}
}
if(!media.disks.empty()) {
target->has_disk_drive = true;
auto &disk = *media.disks.front();
// Check first for a boot track.
if(Storage::Disk::TandyCoCo::has_boot_track(disk)) {
target->loading_command += L"DOS\n";
target->rom_version = Target::ROMVersion::V11OrAbove;
} else {
auto loadable = [&]() -> std::optional<Storage::Disk::TandyCoCo::DirectoryEntry> {
const auto maybe_directory = Storage::Disk::TandyCoCo::directory(disk);
if(!maybe_directory.has_value()) {
return std::nullopt;
}
auto directory = *maybe_directory;
// Remove anything the user can't actually type.
std::erase_if(directory, [](const auto &entry) {
if(entry.name == " ") return true;
for(const auto c: entry.name) {
if(c & 0x80) return true;
}
return false;
});
// Single item: return that.
if(directory.size() == 1) {
return directory[0];
}
// Failing that, is there a single thing that's BASIC or no BASIC and a single thing that's machine code?
int basics = 0;
int machine_languages = 0;
for(const auto &entry: directory) {
basics += entry.file_type == Storage::Disk::TandyCoCo::DirectoryEntry::FileType::BASIC;
machine_languages +=
entry.file_type == Storage::Disk::TandyCoCo::DirectoryEntry::FileType::MachineLanguage;
}
if(basics == 1) {
for(const auto &entry: directory) {
if(entry.file_type == Storage::Disk::TandyCoCo::DirectoryEntry::FileType::BASIC) {
return entry;
}
}
}
if(!basics && machine_languages == 1) {
for(const auto &entry: directory) {
if(entry.file_type == Storage::Disk::TandyCoCo::DirectoryEntry::FileType::MachineLanguage) {
return entry;
}
}
}
return std::nullopt;
} ();
if(loadable.has_value()) {
const bool is_basic = loadable->file_type == Storage::Disk::TandyCoCo::DirectoryEntry::FileType::BASIC;
target->loading_command = is_basic ? L"RUN\"" : L"LOADM\"";
target->loading_command += std::wstring(loadable->name.begin(), loadable->name.end());
if(!is_basic) {
target->loading_command += L"\":EXEC";
}
target->loading_command += L"\n";
} else {
target->loading_command = L"DIR\n";
}
}
}
targets.push_back(std::move(target));
return targets;
}