LaunchAPPL: modularize; Executor and MiniVMac backends for now

This commit is contained in:
Wolfgang Thaller 2017-10-02 23:06:50 +02:00
parent 270cafaab4
commit 5961d1884d
13 changed files with 547 additions and 299 deletions

View File

@ -1,20 +1,27 @@
enable_testing()
set(RETRO68_TEST_CONFIG "-eminivmac" "-t4" "--minivmac-dir=/home/wolfgang/Emulators"
"--system-image=/home/wolfgang/Emulators/baresystem.dsk"
"--autoquit-image=/home/wolfgang/Emulators/vmac extras/autoquit-1.1.1.dsk")
add_application(ReallyEmpty ReallyEmpty.c)
add_test(NAME ReallyEmpty COMMAND LaunchAPPL -e ReallyEmpty.bin)
if(CMAKE_SYSTEM_NAME MATCHES Retro68)
set_target_properties(ReallyEmpty PROPERTIES LINK_FLAGS "-Wl,-gc-sections -Wl,--mac-single")
endif()
add_test(NAME ReallyEmpty COMMAND LaunchAPPL ${RETRO68_TEST_CONFIG} ReallyEmpty.bin)
add_application(Empty Empty.c)
add_test(NAME Empty COMMAND LaunchAPPL -e Empty.bin)
add_test(NAME Empty COMMAND LaunchAPPL ${RETRO68_TEST_CONFIG} Empty.bin)
add_application(File File.c)
add_test(NAME File
COMMAND LaunchAPPL -e File.bin --logfile=out -t5
COMMAND LaunchAPPL ${RETRO68_TEST_CONFIG} File.bin
)
set_tests_properties(File PROPERTIES PASS_REGULAR_EXPRESSION "OK")
add_application(Timeout Timeout.c)
add_test(NAME Timeout
COMMAND sh -c "! LaunchAPPL -e Timeout.bin --logfile=out -t2"
)
set_tests_properties(Timeout PROPERTIES PASS_REGULAR_EXPRESSION "One;Two"
FAIL_REGULAR_EXPRESSION "Three")
add_application(Log Log.c)
add_test(NAME Log
COMMAND LaunchAPPL ${RETRO68_TEST_CONFIG} Log.bin
)
set_tests_properties(Log PROPERTIES PASS_REGULAR_EXPRESSION "One\nTwo\nThree")

View File

@ -4,8 +4,6 @@ int main()
{
TEST_LOG_SIZED("One",3);
TEST_LOG_SIZED("Two",3);
for(;;)
;
TEST_LOG_SIZED("Three",5);
return 0;
}

View File

@ -1,6 +1,13 @@
find_package(Boost COMPONENTS filesystem program_options)
add_executable(LaunchAPPL LaunchAPPL.cc bootblock.c)
add_executable(LaunchAPPL
LaunchAPPL.cc bootblock.c
LaunchMethod.h LaunchMethod.cc
Launcher.h Launcher.cc
Executor.h Executor.cc
MiniVMac.h MiniVMac.cc)
target_include_directories(LaunchAPPL PRIVATE ${CMAKE_INSTALL_PREFIX}/include ${Boost_INCLUDE_DIR})
target_link_libraries(LaunchAPPL ResourceFiles ${Boost_LIBRARIES})

48
LaunchAPPL/Executor.cc Normal file
View File

@ -0,0 +1,48 @@
#include "Executor.h"
#include "Launcher.h"
namespace po = boost::program_options;
class ExecutorLauncher : public Launcher
{
public:
ExecutorLauncher(po::variables_map& options);
virtual ~ExecutorLauncher();
virtual bool Go(int timeout = 0);
};
ExecutorLauncher::ExecutorLauncher(po::variables_map &options)
: Launcher(options, ResourceFile::Format::percent_appledouble)
{
}
ExecutorLauncher::~ExecutorLauncher()
{
}
bool ExecutorLauncher::Go(int timeout)
{
return ChildProcess(options["executor-path"].as<std::string>(), { appPath.string() }, timeout) == 0;
}
void Executor::GetOptions(options_description &desc)
{
desc.add_options()
("executor-path", po::value<std::string>()->default_value("executor"),"path to executor")
;
}
bool Executor::CheckOptions(variables_map &options)
{
return options.count("executor-path") != 0;
}
std::unique_ptr<Launcher> Executor::MakeLauncher(variables_map &options)
{
return std::unique_ptr<Launcher>(new ExecutorLauncher(options));
}

16
LaunchAPPL/Executor.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef EXECUTOR_H
#define EXECUTOR_H
#include "LaunchMethod.h"
class Executor : public LaunchMethod
{
public:
virtual std::string GetName() { return "executor"; }
virtual void GetOptions(options_description& desc);
virtual bool CheckOptions(variables_map& options);
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
};
#endif // EXECUTOR_H

View File

@ -5,18 +5,11 @@
#include <vector>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "ResourceFork.h"
#include "ResourceFile.h"
extern "C" {
#include "hfs.h"
}
#include "LaunchMethod.h"
#include "Launcher.h"
#include "Executor.h"
#include "MiniVMac.h"
namespace po = boost::program_options;
namespace fs = boost::filesystem;
@ -34,105 +27,20 @@ static void usage()
}
int ChildProcess(string program, vector<string> args)
{
std::vector<const char*> argv;
argv.push_back(program.c_str());
for(string& s : args)
argv.push_back(s.c_str());
argv.push_back(NULL);
int timeout = options.count("timeout") ? options["timeout"].as<int>() : 0;
pid_t pid = fork();
if(pid < 0)
{
perror("unable to fork");
return 1;
}
else if(pid == 0)
{
pid_t worker_pid = timeout ? fork() : 0;
if(worker_pid < 0)
{
perror("unable to fork");
_exit(1);
}
if(worker_pid == 0)
{
execvp(argv[0], const_cast<char* const *> (argv.data()));
perror("exec failed");
_exit(1);
}
pid_t timeout_pid = fork();
if(timeout_pid < 0)
{
perror("unable to fork");
_exit(1);
}
if(timeout_pid == 0)
{
sleep(timeout);
_exit(0);
}
int wstatus;
pid_t exited_pid = wait(&wstatus);
if(exited_pid == worker_pid)
{
kill(timeout_pid, SIGKILL);
wait(NULL);
if(!WIFEXITED(wstatus))
{
return 1;
}
else
{
int exitcode = WEXITSTATUS(wstatus);
_exit(exitcode);
}
}
else
{
kill(worker_pid, SIGKILL);
wait(NULL);
_exit(1);
}
}
else
{
int wstatus;
int result = 0;
do
{
result = waitpid(pid, &wstatus, 0);
} while(result == -1 && errno == EINTR);
if(!WIFEXITED(wstatus))
{
return 1;
}
else
{
int exitcode = WEXITSTATUS(wstatus);
return exitcode;
}
}
}
int main(int argc, char *argv[])
{
std::vector<LaunchMethod*> methods = {
new Executor(), new MiniVMac()
};
desc.add_options()
("help,h", "show this help message")
("executor,e", "run using executor")
("minivmac,m", "run using executor")
("executor-path", po::value<std::string>()->default_value("executor"),"path to executor")
("minivmac-path", po::value<std::string>()->default_value("minivmac"),"path to minivmac")
("minivmac-dir", po::value<std::string>()->default_value("."),"directory containing vMac.ROM")
("system-image", po::value<std::string>(),"path to disk image with system")
("emulator,e", po::value<std::string>(), "what emulator/environment to use")
;
for(LaunchMethod *lm : methods)
lm->GetOptions(desc);
desc.add_options()
("timeout,t", po::value<int>(),"abort after timeout")
("timeout-ok","timeout counts as success")
("logfile", po::value<std::string>(), "read log file")
@ -142,7 +50,6 @@ int main(int argc, char *argv[])
("application,a", po::value<std::string>(), "application" )
;
alldesc.add(desc).add(hidden);
try
{
auto parsed = po::command_line_parser(argc, argv)
@ -162,198 +69,41 @@ int main(int argc, char *argv[])
po::notify(options);
if(options.count("help") || !options.count("application"))
if(options.count("help") || !options.count("application") || !options.count("emulator"))
{
usage();
return 0;
}
ResourceFile app(options["application"].as<std::string>());
if(!app.read())
LaunchMethod *method = NULL;
for(LaunchMethod *lm : methods)
{
std::cerr << "Could not read application file.\n";
if(lm->GetName() == options["emulator"].as<string>())
{
method = lm;
break;
}
}
if(!method)
{
std::cerr << "ERROR: unknown emulator/environment.\n";
return 1;
}
if(options.count("executor"))
if(!method->CheckOptions(options))
{
fs::path tempDir = fs::unique_path();
fs::create_directories(tempDir);
fs::path appPath = tempDir / "Application";
app.assign(appPath.string(), ResourceFile::Format::percent_appledouble);
if(!app.write())
{
std::cerr << "Could not write application file.\n";
return 1;
}
if(options.count("logfile"))
{
fs::ofstream out(tempDir/options["logfile"].as<std::string>());
}
int result = ChildProcess(options["executor-path"].as<std::string>(), { appPath.string() });
if(options.count("logfile"))
{
fs::ifstream in(tempDir/options["logfile"].as<std::string>());
std::cout << in.rdbuf();
}
fs::remove_all(tempDir);
return result;
}
if(options.count("minivmac"))
{
assert(options.count("system-image"));
fs::path tempDir = fs::unique_path();
fs::path path = tempDir / "image.dsk";
fs::create_directories(tempDir);
hfsvol *sysvol = hfs_mount(options["system-image"].as<std::string>().c_str(),
0, HFS_MODE_RDONLY);
int size = 5000*1024;
fs::ofstream(path, std::ios::binary | std::ios::trunc).seekp(size-1).put(0);
hfs_format(path.string().c_str(), 0, 0, "SysAndApp", 0, NULL);
hfsvol *vol = hfs_mount(path.string().c_str(), 0, HFS_MODE_RDWR);
hfsvolent ent;
hfs_vstat(sysvol, &ent);
hfs_setcwd(sysvol, ent.blessed);
{
const char *fn = "System";
hfsdirent fileent;
hfs_stat(sysvol, fn, &fileent);
hfsfile *in = hfs_open(sysvol, fn);
hfsfile *out = hfs_create(vol, fn, fileent.u.file.type,fileent.u.file.creator);
std::vector<uint8_t> buffer(std::max(fileent.u.file.dsize, fileent.u.file.rsize));
hfs_setfork(in, 0);
hfs_setfork(out, 0);
hfs_read(in, buffer.data(), fileent.u.file.dsize);
hfs_write(out, buffer.data(), fileent.u.file.dsize);
hfs_setfork(in, 1);
hfs_setfork(out, 1);
hfs_read(in, buffer.data(), fileent.u.file.rsize);
hfs_write(out, buffer.data(), fileent.u.file.rsize);
hfs_close(in);
hfs_close(out);
}
{
const char *fn = "Finder";
hfsdirent fileent;
hfs_stat(sysvol, fn, &fileent);
hfsfile *in = hfs_open(sysvol, fn);
hfsfile *out = hfs_create(vol, fn, fileent.u.file.type,fileent.u.file.creator);
std::vector<uint8_t> buffer(std::max(fileent.u.file.dsize, fileent.u.file.rsize));
hfs_setfork(in, 0);
hfs_setfork(out, 0);
hfs_read(in, buffer.data(), fileent.u.file.dsize);
hfs_write(out, buffer.data(), fileent.u.file.dsize);
hfs_setfork(in, 1);
hfs_setfork(out, 1);
hfs_read(in, buffer.data(), fileent.u.file.rsize);
hfs_write(out, buffer.data(), fileent.u.file.rsize);
hfs_close(in);
hfs_close(out);
}
{
const char *fn = "MacsBug";
hfsdirent fileent;
hfs_stat(sysvol, fn, &fileent);
hfsfile *in = hfs_open(sysvol, fn);
hfsfile *out = hfs_create(vol, fn, fileent.u.file.type,fileent.u.file.creator);
std::vector<uint8_t> buffer(std::max(fileent.u.file.dsize, fileent.u.file.rsize));
hfs_setfork(in, 0);
hfs_setfork(out, 0);
hfs_read(in, buffer.data(), fileent.u.file.dsize);
hfs_write(out, buffer.data(), fileent.u.file.dsize);
hfs_setfork(in, 1);
hfs_setfork(out, 1);
hfs_read(in, buffer.data(), fileent.u.file.rsize);
hfs_write(out, buffer.data(), fileent.u.file.rsize);
hfs_close(in);
hfs_close(out);
}
{
std::ostringstream rsrcOut;
app.resources.writeFork(rsrcOut);
std::string rsrc = rsrcOut.str();
std::string& data = app.data;
hfsfile *file = hfs_create(vol, "App","APPL","????");
hfs_setfork(file, 0);
hfs_write(file, data.data(), data.size());
hfs_setfork(file, 1);
hfs_write(file, rsrc.data(), rsrc.size());
hfs_close(file);
}
{
hfsfile *out = hfs_create(vol, "out", "TEXT", "????");
hfs_close(out);
}
hfs_vstat(vol, &ent);
ent.blessed = hfs_getcwd(vol);
std::cout << "blessed: " << ent.blessed << std::endl;
hfs_vsetattr(vol, &ent);
hfs_umount(vol);
hfs_umount(sysvol);
extern unsigned char bootblock[1024];
std::vector<unsigned char> bootblock1(bootblock, bootblock+1024);
std::fstream out(path.string(), std::ios::in | std::ios::out | std::ios::binary);
bootblock1[0x5A] = 3;
bootblock1[0x5B] = 'A';
bootblock1[0x5C] = 'p';
bootblock1[0x5D] = 'p';
out.write((const char*) bootblock1.data(), 1024);
path = fs::absolute(path);
fs::path minivmacdir = fs::absolute( options["minivmac-dir"].as<std::string>() );
fs::path minivmacpath = fs::absolute( minivmacdir / options["minivmac-path"].as<std::string>() );
fs::current_path(minivmacdir);
int result = ChildProcess(minivmacpath.string(), { path.string() });
std::cerr << "volume at: " << path.string() << std::endl;
vol = hfs_mount(path.string().c_str(), 0, HFS_MODE_RDONLY);
{
hfsfile *out = hfs_open(vol, "out");
if(!out)
return 1;
hfsdirent fileent;
int statres = hfs_stat(vol, "out", &fileent);
std::cerr << "stat: " << statres << "\n";
std::cerr << "out: " << fileent.u.file.dsize << " bytes\n";
std::vector<char> buffer(fileent.u.file.dsize);
hfs_setfork(out, 0);
hfs_read(out, buffer.data(), fileent.u.file.dsize);
hfs_close(out);
std::cout << string(buffer.begin(), buffer.end());
}
hfs_umount(vol);
std::cerr << "Missing configuration.\n";
return 1;
}
return 0;
std::unique_ptr<Launcher> launcher = method->MakeLauncher(options);
int timeout = options.count("timeout") ? options["timeout"].as<int>() : 0;
bool result = launcher->Go(timeout);
launcher->DumpOutput();
return result ? 0 : 1;
}

View File

@ -0,0 +1,20 @@
#include "LaunchMethod.h"
LaunchMethod::LaunchMethod()
{
}
LaunchMethod::~LaunchMethod()
{
}
void LaunchMethod::GetOptions(boost::program_options::options_description &desc)
{
}
bool LaunchMethod::CheckOptions(boost::program_options::variables_map &options)
{
return true;
}

28
LaunchAPPL/LaunchMethod.h Normal file
View File

@ -0,0 +1,28 @@
#ifndef LAUNCHMETHOD_H
#define LAUNCHMETHOD_H
#include <string>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/variables_map.hpp>
#include <memory>
class Launcher;
class LaunchMethod
{
public:
typedef boost::program_options::options_description options_description;
typedef boost::program_options::variables_map variables_map;
LaunchMethod();
virtual ~LaunchMethod();
virtual std::string GetName() = 0;
virtual void GetOptions(options_description& desc);
virtual bool CheckOptions(variables_map& options);
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options) = 0;
};
#endif // LAUNCHMETHOD_H

132
LaunchAPPL/Launcher.cc Normal file
View File

@ -0,0 +1,132 @@
#include "Launcher.h"
#include <boost/filesystem/fstream.hpp>
#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
namespace fs = boost::filesystem;
using std::string;
using std::vector;
Launcher::Launcher(boost::program_options::variables_map &options)
: options(options)
{
app.assign(options["application"].as<std::string>());
if(!app.read())
throw std::runtime_error("Could not load application file.");
tempDir = fs::absolute(fs::unique_path());
fs::create_directories(tempDir);
appPath = tempDir / "Application";
outPath = tempDir / "out";
fs::ofstream out(outPath);
}
Launcher::Launcher(boost::program_options::variables_map &options, ResourceFile::Format f)
: Launcher(options)
{
app.assign(appPath.string(), f);
app.write();
}
void Launcher::DumpOutput()
{
fs::ifstream in(outPath);
std::cout << in.rdbuf();
}
Launcher::~Launcher()
{
fs::remove_all(tempDir);
}
int Launcher::ChildProcess(string program, vector<string> args, int timeout)
{
std::vector<const char*> argv;
argv.push_back(program.c_str());
for(string& s : args)
argv.push_back(s.c_str());
argv.push_back(NULL);
pid_t pid = fork();
if(pid < 0)
{
perror("unable to fork");
return 1;
}
else if(pid == 0)
{
pid_t worker_pid = timeout ? fork() : 0;
if(worker_pid < 0)
{
perror("unable to fork");
_exit(1);
}
if(worker_pid == 0)
{
execvp(argv[0], const_cast<char* const *> (argv.data()));
perror("exec failed");
_exit(1);
}
pid_t timeout_pid = fork();
if(timeout_pid < 0)
{
perror("unable to fork");
_exit(1);
}
if(timeout_pid == 0)
{
sleep(timeout);
_exit(0);
}
int wstatus;
pid_t exited_pid = wait(&wstatus);
if(exited_pid == worker_pid)
{
kill(timeout_pid, SIGKILL);
wait(NULL);
if(!WIFEXITED(wstatus))
{
return 1;
}
else
{
int exitcode = WEXITSTATUS(wstatus);
_exit(exitcode);
}
}
else
{
kill(worker_pid, SIGKILL);
wait(NULL);
_exit(1);
}
}
else
{
int wstatus;
int result = 0;
do
{
result = waitpid(pid, &wstatus, 0);
} while(result == -1 && errno == EINTR);
if(!WIFEXITED(wstatus))
{
return 1;
}
else
{
int exitcode = WEXITSTATUS(wstatus);
return exitcode;
}
}
}

31
LaunchAPPL/Launcher.h Normal file
View File

@ -0,0 +1,31 @@
#ifndef LAUNCHER_H
#define LAUNCHER_H
#include <boost/program_options/variables_map.hpp>
#include "ResourceFile.h"
#include <boost/filesystem.hpp>
class Launcher
{
protected:
boost::program_options::variables_map& options;
ResourceFile app;
boost::filesystem::path tempDir, appPath, outPath;
bool keepTempFiles;
int ChildProcess(std::string program, std::vector<std::string> args, int timeout);
public:
Launcher(boost::program_options::variables_map& options);
Launcher(boost::program_options::variables_map& options, ResourceFile::Format f);
void KeepTempFiles() { keepTempFiles = true; }
virtual bool Go(int timeout = 0) = 0;
virtual void DumpOutput();
virtual ~Launcher();
};
#endif // LAUNCHER_H

195
LaunchAPPL/MiniVMac.cc Normal file
View File

@ -0,0 +1,195 @@
#include "MiniVMac.h"
#include "Launcher.h"
extern "C" {
#include "hfs.h"
}
#include <iostream>
namespace fs = boost::filesystem;
using std::string;
using std::vector;
namespace po = boost::program_options;
namespace fs = boost::filesystem;
class MiniVMacLauncher : public Launcher
{
fs::path imagePath;
fs::path systemImage;
hfsvol *sysvol;
hfsvol *vol;
void CopySystemFile(const char* fn, const char *dstfn = NULL);
public:
MiniVMacLauncher(po::variables_map& options);
virtual ~MiniVMacLauncher();
virtual bool Go(int timeout = 0);
virtual void DumpOutput();
};
MiniVMacLauncher::MiniVMacLauncher(po::variables_map &options)
: Launcher(options, ResourceFile::Format::percent_appledouble),
sysvol(NULL), vol(NULL)
{
imagePath = fs::absolute(tempDir / "image.dsk");
systemImage = fs::absolute(options["system-image"].as<std::string>());
fs::path autoquitImage = fs::absolute(options["autoquit-image"].as<std::string>());
sysvol = hfs_mount(systemImage.string().c_str(),0, HFS_MODE_RDONLY);
assert(sysvol);
hfsvolent ent;
hfs_vstat(sysvol, &ent);
hfs_setcwd(sysvol, ent.blessed);
int size = 5000*1024;
fs::ofstream(imagePath, std::ios::binary | std::ios::trunc).seekp(size-1).put(0);
hfs_format(imagePath.string().c_str(), 0, 0, "SysAndApp", 0, NULL);
{
extern unsigned char bootblock[1024];
std::vector<unsigned char> bootblock1(bootblock, bootblock+1024);
bootblock1[0x1A] = 8;
memcpy(&bootblock1[0x1B],"AutoQuit", 8);
bootblock1[0x5A] = 3;
memcpy(&bootblock1[0x5B],"App", 3);
std::fstream(imagePath.string(), std::ios::in | std::ios::out | std::ios::binary)
.write((const char*) bootblock1.data(), 1024);
}
vol = hfs_mount(imagePath.string().c_str(), 0, HFS_MODE_RDWR);
assert(vol);
hfs_vstat(vol, &ent);
ent.blessed = hfs_getcwd(vol);
hfs_vsetattr(vol, &ent);
CopySystemFile("System");
CopySystemFile("Finder");
CopySystemFile("MacsBug");
{
std::ostringstream rsrcOut;
app.resources.writeFork(rsrcOut);
std::string rsrc = rsrcOut.str();
std::string& data = app.data;
hfsfile *file = hfs_create(vol, "App","APPL","????");
hfs_setfork(file, 0);
hfs_write(file, data.data(), data.size());
hfs_setfork(file, 1);
hfs_write(file, rsrc.data(), rsrc.size());
hfs_close(file);
}
hfs_umount(sysvol);
sysvol = hfs_mount(autoquitImage.string().c_str(),0, HFS_MODE_RDONLY);
assert(sysvol);
CopySystemFile("AutoQuit");
{
hfsfile *file = hfs_create(vol, "out", "TEXT", "MPS ");
hfs_close(file);
}
hfs_umount(sysvol); sysvol = NULL;
hfs_umount(vol); vol = NULL;
}
MiniVMacLauncher::~MiniVMacLauncher()
{
if(sysvol)
hfs_umount(sysvol);
if(vol)
hfs_umount(vol);
}
void MiniVMacLauncher::CopySystemFile(const char *fn, const char *dstfn)
{
if(!dstfn)
dstfn = fn;
hfsdirent fileent;
if(hfs_stat(sysvol, fn, &fileent) < 0)
return;
hfsfile *in = hfs_open(sysvol, fn);
hfsfile *out = hfs_create(vol, dstfn, fileent.u.file.type,fileent.u.file.creator);
std::vector<uint8_t> buffer(std::max(fileent.u.file.dsize, fileent.u.file.rsize));
hfs_setfork(in, 0);
hfs_setfork(out, 0);
hfs_read(in, buffer.data(), fileent.u.file.dsize);
hfs_write(out, buffer.data(), fileent.u.file.dsize);
hfs_setfork(in, 1);
hfs_setfork(out, 1);
hfs_read(in, buffer.data(), fileent.u.file.rsize);
hfs_write(out, buffer.data(), fileent.u.file.rsize);
hfs_close(in);
hfs_close(out);
}
bool MiniVMacLauncher::Go(int timeout)
{
fs::path minivmacdir = fs::absolute( options["minivmac-dir"].as<std::string>() );
std::string minivmacpath = options["minivmac-path"].as<std::string>();
fs::current_path(minivmacdir);
return ChildProcess(minivmacpath, { imagePath.string() }, timeout) == 0;
}
void MiniVMacLauncher::DumpOutput()
{
sleep(1);
vol = hfs_mount(imagePath.string().c_str(), 0, HFS_MODE_RDONLY);
hfsdirent fileent;
int statres = hfs_stat(vol, "out", &fileent);
std::cerr << "stat: " << statres << "\n";
std::cerr << "out: " << fileent.u.file.dsize << " bytes\n";
hfsfile *out = hfs_open(vol, "out");
if(!out)
return;
std::vector<char> buffer(fileent.u.file.dsize);
hfs_setfork(out, 0);
hfs_read(out, buffer.data(), fileent.u.file.dsize);
hfs_close(out);
std::cout << string(buffer.begin(), buffer.end());
hfs_umount(vol); vol = NULL;
}
void MiniVMac::GetOptions(options_description &desc)
{
desc.add_options()
("minivmac-dir", po::value<std::string>(),"directory containing vMac.ROM")
("minivmac-path", po::value<std::string>()->default_value("./minivmac"),"relative path to minivmac")
("system-image", po::value<std::string>(),"path to disk image with system")
("autoquit-image", po::value<std::string>(),"path to autoquit disk image, available from the minivmac web site")
;
}
bool MiniVMac::CheckOptions(variables_map &options)
{
return options.count("minivmac-path") != 0
&& options.count("minivmac-dir") != 0
&& options.count("system-image") != 0
&& options.count("autoquit-image") != 0;
}
std::unique_ptr<Launcher> MiniVMac::MakeLauncher(variables_map &options)
{
return std::unique_ptr<Launcher>(new MiniVMacLauncher(options));
}

16
LaunchAPPL/MiniVMac.h Normal file
View File

@ -0,0 +1,16 @@
#ifndef MINIVMAC_H
#define MINIVMAC_H
#include "LaunchMethod.h"
class MiniVMac : public LaunchMethod
{
public:
virtual std::string GetName() { return "minivmac"; }
virtual void GetOptions(options_description& desc);
virtual bool CheckOptions(variables_map& options);
virtual std::unique_ptr<Launcher> MakeLauncher(variables_map& options);
};
#endif // MINIVMAC_H

BIN
LaunchAPPL/bootblock Normal file

Binary file not shown.