28 :
Command(commandController_, basename)
29 , interface(interface_)
34 const string& basename,
unsigned n,
MSXMotherBoard& motherBoard)
const
36 return std::make_unique<DiskChanger>(
45 if (drv->isRomDisk()) {
52void NowindCommand::processHdimage(
63 if (
auto pos = hdImage.find_last_of(
':');
66 std::string_view(hdImage).
substr(pos + 1), 1, 31);
69 auto wholeDisk = std::make_shared<DSKDiskImage>(
Filename(hdImage));
70 bool failOnError =
true;
71 if (partitions.
empty()) {
82 auto partition = std::make_unique<DiskPartition>(
83 *wholeDisk,
unsigned(p),
84 std::shared_ptr<SectorAccessibleDisk>(wholeDisk));
86 interface.basename,
unsigned(drives.size()),
88 drive->changeDisk(std::unique_ptr<Disk>(std::move(
partition)));
89 drives.push_back(std::move(drive));
90 }
catch (MSXException&) {
91 if (failOnError)
throw;
98 auto& host = interface.host;
99 auto& drives = interface.drives;
100 unsigned oldRomDisk = searchRomDisk(drives);
102 if (tokens.size() == 1) {
104 assert(!drives.empty());
106 for (
auto [i, drv] :
enumerate(drives)) {
110 }
else if (
const auto* changer =
dynamic_cast<const DiskChanger*
>(
112 string filename = changer->getDiskName().getOriginal();
113 strAppend(r, (filename.empty() ?
"--empty--" : filename),
120 (host.getEnablePhantomDrives() ?
"enabled" :
"disabled"),
122 "allow other diskroms: ",
123 (host.getAllowOtherDiskRoms() ?
"yes" :
"no"),
130 bool enablePhantom =
false;
131 bool disablePhantom =
false;
132 bool allowOther =
false;
133 bool disallowOther =
false;
134 bool changeDrives =
false;
135 unsigned romDisk = 255;
140 std::span<const TclObject> args(&tokens[1], tokens.size() - 1);
141 while (error.empty() && !args.empty()) {
142 bool createDrive =
false;
143 std::string_view
image;
145 std::string_view arg = args.front().getString();
146 args = args.subspan(1);
147 if (arg ==
one_of(
"--ctrl",
"-c")) {
148 enablePhantom =
false;
149 disablePhantom =
true;
150 }
else if (arg ==
one_of(
"--no-ctrl",
"-C")) {
151 enablePhantom =
true;
152 disablePhantom =
false;
153 }
else if (arg ==
one_of(
"--allow",
"-a")) {
155 disallowOther =
false;
156 }
else if (arg ==
one_of(
"--no-allow",
"-A")) {
158 disallowOther =
true;
160 }
else if (arg ==
one_of(
"--romdisk",
"-j")) {
161 if (romDisk != 255) {
162 error =
"Can only have one romdisk";
164 romDisk = unsigned(tmpDrives.size());
165 tmpDrives.push_back(std::make_unique<NowindRomDisk>());
169 }
else if (arg ==
one_of(
"--image",
"-i")) {
171 error =
strCat(
"Missing argument for option: ", arg);
173 image = args.front().getString();
174 args = args.subspan(1);
178 }
else if (arg ==
one_of(
"--hdimage",
"-m")) {
180 error =
strCat(
"Missing argument for option: ", arg);
184 string(args.front().getString()));
185 args = args.subspan(1);
186 processHdimage(hdImage, tmpDrives);
189 error = std::move(e).getMessage();
201 interface.basename,
unsigned(tmpDrives.size()),
204 if (!
image.empty()) {
209 tmpDrives.push_back(std::move(drive));
212 if (tmpDrives.size() > 8) {
213 error =
"Can't have more than 8 drives";
217 bool optionsChanged =
false;
219 if (enablePhantom && !host.getEnablePhantomDrives()) {
220 host.setEnablePhantomDrives(
true);
221 optionsChanged =
true;
223 if (disablePhantom && host.getEnablePhantomDrives()) {
224 host.setEnablePhantomDrives(
false);
225 optionsChanged =
true;
227 if (allowOther && !host.getAllowOtherDiskRoms()) {
228 host.setAllowOtherDiskRoms(
true);
229 optionsChanged =
true;
231 if (disallowOther && host.getAllowOtherDiskRoms()) {
232 host.setAllowOtherDiskRoms(
false);
233 optionsChanged =
true;
236 std::swap(tmpDrives, drives);
243 auto prevSize = tmpDrives.size();
245 for (
const auto& d : drives) {
246 if (
auto* disk =
dynamic_cast<DiskChanger*
>(d.get())) {
247 disk->createCommand();
251 if (!error.empty()) {
257 if (changeDrives && (prevSize != drives.size())) {
258 r +=
"Number of drives changed. ";
260 if (changeDrives && (romDisk != oldRomDisk)) {
261 if (oldRomDisk == 255) {
262 r +=
"Romdisk added. ";
263 }
else if (romDisk == 255) {
264 r +=
"Romdisk removed. ";
266 r +=
"Romdisk changed position. ";
269 if (optionsChanged) {
270 r +=
"Boot options changed. ";
273 r +=
"You may need to reset the MSX for the changes to take effect.";
280 return "Similar to the disk<x> commands there is a nowind<x> command "
281 "for each nowind interface. This command is modeled after the "
282 "'usbhost' command of the real nowind interface. Though only a "
283 "subset of the options is supported. Here's a short overview.\n"
285 "Command line options\n"
286 " long short explanation\n"
287 "--image -i specify disk image\n"
288 "--hdimage -m specify hard disk image\n"
289 "--romdisk -j enable romdisk\n"
291 "--ctrl -c no phantom disks\n"
292 "--no-ctrl -C enable phantom disks\n"
293 "--allow -a allow other disk roms to initialize\n"
294 "--no-allow -A don't allow other disk roms to initialize\n"
300 "If you don't pass any arguments to this command, you'll get "
301 "an overview of the current nowind status.\n"
303 "This command will create a certain amount of drives on the "
304 "nowind interface and (optionally) insert disk images in those "
305 "drives. For each of these drives there will also be a "
306 "'nowind<1..8>' command created. Those commands are similar to "
307 "e.g. the diska command. They can be used to access the more "
308 "advanced disk image insertion options. See 'help nowind<1..8>' "
311 "In some cases it is needed to reboot the MSX before the "
312 "changes take effect. In those cases you'll get a message "
313 "that warns about this.\n"
316 "nowinda -a image.dsk -j Image.dsk is inserted into drive A: and the romdisk\n"
317 " will be drive B:. Other disk roms will be able to\n"
318 " install drives as well. For example when the MSX has\n"
319 " an internal disk drive, drive C: en D: will be\n"
320 " available as well.\n"
321 "nowinda disk1.dsk disk2.dsk The two images will be inserted in A: and B:\n"
323 "nowinda -m hdimage.dsk Inserts a hard disk image. All available partitions\n"
324 " will be mounted as drives.\n"
325 "nowinda -m hdimage.dsk:1 Inserts the first partition only.\n"
326 "nowinda -m hdimage.dsk:2-4 Inserts the 2nd, 3th and 4th partition as drive A:\n"
332 using namespace std::literals;
333 static constexpr std::array extra = {
335 "-C"sv,
"--no-ctrl"sv,
337 "-A"sv,
"--no-allow"sv,
338 "-j"sv,
"--romdisk"sv,
340 "-m"sv,
"--hdimage"sv,
bool empty() const
(Implicit) default constructor.
void setRange(size_t begin, size_t end)
Set all bits in the half-open range [begin, end) to '1'.
void foreachSetBit(std::invocable< size_t > auto op) const
Execute the given operation 'op' for all '1' bits.
static void completeFileName(std::vector< std::string > &tokens, const FileContext &context, const RANGE &extra)
MSXMotherBoard & getMotherBoard() const
Get the mother board this device belongs to.
void execute(std::span< const TclObject > tokens, TclObject &result) override
Execute this command.
NowindCommand(const std::string &basename, CommandController &commandController, NowindInterface &interface)
std::string help(std::span< const TclObject > tokens) const override
Print help for this command.
void tabCompletion(std::vector< std::string > &tokens) const override
Attempt tab completion for this command.
std::unique_ptr< DiskChanger > createDiskChanger(const std::string &basename, unsigned n, MSXMotherBoard &motherBoard) const
std::vector< std::unique_ptr< DiskContainer > > Drives
constexpr auto enumerate(Iterable &&iterable)
Heavily inspired by Nathan Reed's blog post: Python-Like enumerate() In C++17 http://reedbeta....
IterableBitSet< 64 > parseRange(string_view str, unsigned min, unsigned max)
unsigned partition(SectorAccessibleDisk &disk, std::span< const unsigned > sizes, MSXBootSectorType bootType)
Write a partition table to the given disk and format each partition.
bool exists(zstring_view filename)
Does this file (directory) exists?
string expandTilde(string path)
Expand the '~' character to the users home directory.
This file implemented 3 utility functions:
const FileContext & userFileContext()
std::string_view substr(std::string_view utf8, std::string_view::size_type first=0, std::string_view::size_type len=std::string_view::npos)
void strAppend(std::string &result, Ts &&...ts)