Grab full first file for analysis.

This commit is contained in:
Thomas Harte committed 2026-04-22 21:17:27 -04:00
1 parent 296c5ed1a7
commit 602b6a115e
4 files changed
+67 -17

No files matched your search

+13 -16
View File
@@ -81,30 +81,27 @@ Analyser::Static::TargetList Analyser::Static::Thomson::GetTargets(
Storage::Tape::Thomson::MO::Parser parser;
auto &tape = media.tapes.front();
const auto serialiser = tape->serialiser();
const auto first = parser.block(*serialiser);
const auto first = parser.file(*serialiser);
if(first && first->checksum_valid()) {
if(first && first->checksums_valid) {
target->media.tapes = media.tapes;
// Cf. https://pulkomandy.tk/wiki/doku.php?id=documentations:monitor:tape.format for leader block format;
// my parser provides block type separately and length implicitly so the type at offset 0xd is at 0xb
// in ->data.
static constexpr size_t TypeOffset = 0xb;
if(!first->type && first->data.size() > TypeOffset) {
const auto command = [&]() -> std::wstring {
if(!first->data[TypeOffset]) { // File type; 0 = BASIC, 1 = DATA; 2 = binary.
return L"RUN\"";
} else {
return L"LOADM\"\",,R";
}
};
// TODO: determine whether BASIC 1 or BASIC 128 is appropriate.
if(DefaultMO6) {
target->loading_command = std::wstring(L"2 ") + command() + L"\n";
const auto command = [&]() -> std::wstring {
if(!first->type) { // File type; 0 = BASIC, 1 = DATA; 2 = binary.
return L"RUN\"";
} else {
target->loading_command = command() + L"\n";
return L"LOADM\"\",,R";
}
};
// TODO: determine whether BASIC 1 or BASIC 128 is appropriate.
if(DefaultMO6) {
target->loading_command = std::wstring(L"2 ") + command() + L"\n";
} else {
target->loading_command = command() + L"\n";
}
}
}
+1 -1
View File
@@ -286,7 +286,7 @@ private:
}
#ifndef NDEBUG
std::atomic_flag flush_concurrency_check_{};
std::atomic_flag flush_concurrency_check_ = ATOMIC_FLAG_INIT;
#endif
};
+38
View File
@@ -92,6 +92,44 @@ std::optional<Block> Parser::block(Storage::Tape::TapeSerialiser &serialiser) {
return result;
}
std::optional<File> Parser::file(Storage::Tape::TapeSerialiser &serialiser) {
std::optional<File> result;
do {
// Find next leader.
const auto leader = block(serialiser);
if(!leader.has_value()) break;
if(leader->type != 0) continue;
if(leader->data.size() != 14) continue;
// Create file.
result = File();
const auto copy_string = [&](auto &target, const size_t offset) {
std::copy_n(leader->data.data() + offset, sizeof(target) - 1, target);
auto end = std::find_if(std::rbegin(target) + 1, std::rend(target), [](const char c) {
return c != ' ';
});
*(end - 1) = '\0';
};
copy_string(result->name, 0);
copy_string(result->extension, 8);
result->type = leader->data[11];
result->mode = uint16_t((leader->data[12] << 8) | leader->data[13]);
// Accumulate data for as long as it comes.
while(true) {
const auto next = block(serialiser);
if(next->type != 1) break;
std::copy(next->data.begin(), next->data.end(), std::back_inserter(result->data));
}
} while(false);
return result;
}
uint8_t Block::check_digit() const {
return uint8_t(checksum - std::accumulate(data.begin(), data.end(), 0));
}
+15
View File
@@ -27,11 +27,26 @@ struct Block {
uint8_t check_digit() const;
};
struct File {
char name[9]{};
char extension[4]{};
std::string filename() const {
return std::string(name) + '.' + extension;
}
uint8_t type = 0;
uint16_t mode = 0;
std::vector<uint8_t> data;
bool checksums_valid = true;
};
class Parser {
public:
std::optional<bool> bit(Storage::Tape::TapeSerialiser &);
std::optional<uint8_t> byte(Storage::Tape::TapeSerialiser &);
std::optional<Block> block(Storage::Tape::TapeSerialiser &);
std::optional<File> file(Storage::Tape::TapeSerialiser &);
void seed_level(Pulse::Type);