-
Notifications
You must be signed in to change notification settings - Fork 37
/
doscommands.cpp
320 lines (254 loc) · 9.71 KB
/
doscommands.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
#include "doscommands.hpp"
#include "interface.hpp"
#include "d64driver.hpp"
#include "logger.hpp"
#include "utils.hpp"
using namespace Logging;
namespace CBMDos {
CommandList Command::s_attached;
namespace {
QString FACDOS("DOSCMD");
// These static commands will auto-attach (register) themselves upon start.
InitDrive initDriveCmd;
ValidateDisk validateDiskCmd;
NewDisk newDiskCmd;
Scratch scratchFileCmd;
RenameFile renameFileCmd;
CopyFiles copyFilesCmd;
SetPosition setPositionCmd;
BlockRead blockReadCmd;
BlockWrite blockWriteCmd;
MemoryRead memoryReadCmd;
MemoryWrite memoryWriteCmd;
BufferPointer bufferPointerCmd;
BlockAllocate blockAllocateCmd;
BlockFree blockFreeCmd;
BlockExecute blockExecuteCmd;
MemoryExecute memoryExecuteCmd;
VC20ModeOnOff vc20ModeOnOffCmd;
DeviceAddress deviceAddressCmd;
ChangeDirectory chDirCmd;
MakeDirectory makeDirCmd;
RemoveDirectory rmDirCmd;
}
CBM::IOErrorMessage InitDrive::process(const QByteArray& params, Interface& iface)
{
// Either ignore or check that no parameters are given here!
Q_UNUSED(params);
return iface.reset();
} // InitDrive
CBM::IOErrorMessage ValidateDisk::process(const QByteArray& params, Interface& iface)
{
Q_UNUSED(params);
Q_UNUSED(iface);
return CBM::ErrNotImplemented;
} // ValidateDisk
CBM::IOErrorMessage NewDisk::process(const QByteArray ¶ms, Interface &iface)
{
CBM::IOErrorMessage result;
QStringList newParams(QString(params).split(',', QString::SkipEmptyParts));
if(newParams.empty() or newParams.count() > 2)
return CBM::ErrSyntaxError;
if(iface.isDiskWriteProtected())
return CBM::ErrWriteProtectOn;
FileDriverBase* driver = NULL;
const QString label(newParams[0]);
bool hasExt = hasExtension(label);
// prefer using current driver...
if(NULL not_eq iface.currentFileDriver()) {
// ...but only if it supports the extension or the disk label was specified without extension.
if(iface.currentFileDriver()->supportsType(label) or not hasExt)
driver = iface.currentFileDriver();
}
if(NULL == driver and hasExt)
driver = iface.driverForFile(label);
if(driver) {
// if we got a driver, use that to do the newdisk but without extension.
QString id(newParams.count() > 1 ? newParams[1] : QString());
result = driver->newDisk(withoutExtension(label), id);
}
else
result = CBM::ErrDriveNotReady; // Probably best error suitable for this situation.
return result;
} // NewDisk
CBM::IOErrorMessage Scratch::process(const QByteArray ¶ms, Interface &iface)
{
const QString file(params);
if(iface.isDiskWriteProtected())
return CBM::ErrWriteProtectOn;
// TODO: Check that there is no path stuff in the name, we don't like that here.
// TODO: Support drive number (e.g. S0:<file>)
Log(FACDOS, info, QString("About to scratch file: %1").arg(file));
return iface.currentFileDriver()->deleteFile(file) ? CBM::ErrFilesScratched : CBM::ErrFileNotFound;
} // Scratch
CBM::IOErrorMessage RenameFile::process(const QByteArray& params, Interface& iface)
{
const QStringList names(QString(params).split(QChar('=')));
// old name and new name must be present, no more no less.
if(2 not_eq names.count())
return CBM::ErrSyntaxError;
const QString oldName(names[0]);
const QString newName(names[1]);
// None of the names may be empty.
if(oldName.isEmpty() or newName.isEmpty())
return CBM::ErrNoFileGiven;
// Check for any illegal characters. This is VERY platform specific for the native file systems, and only the real
// rename will tell if this succeeds or not. But we may precheck in same way as sd2iec.
if(isIllegalCBMName(newName))
return CBM::ErrSyntaxError;
// The new file must NOT already exist.
if(iface.currentFileDriver()->fileExists(newName))
return CBM::ErrFileExists;
// Check if old file exists.
if(not iface.currentFileDriver()->fileExists(oldName))
return CBM::ErrFileNotFound;
if(iface.isDiskWriteProtected())
return CBM::ErrWriteProtectOn;
// NOTE: Need to check here whether the file is renamed across paths or not?
Log(FACDOS, info, QString("About to rename file: %1 to %2").arg(oldName, newName));
// Let the current file system decide whether it goes well by doing the rename operation.
return iface.currentFileDriver()->renameFile(oldName, newName);
} // RenameFile
CBM::IOErrorMessage CopyFiles::process(const QByteArray& params, Interface& iface)
{
Log(FACDOS, info, QString("Reached copy1"));
const QStringList paramList(QString(params).split(QChar('=')));
// destination name and source name(s) parameters must be present, no more no less.
if(2 not_eq paramList.count())
return CBM::ErrSyntaxError;
const QString destName(paramList[0]);
// destination name must not be empty it they must have legal characters.
if(destName.isEmpty())
return CBM::ErrNoFileGiven;
Log(FACDOS, info, QString("Reached copy2:%1").arg(destName));
if(isIllegalCBMName(destName))
return CBM::ErrSyntaxError;
Log(FACDOS, info, QString("Reached copy3"));
if(iface.isDiskWriteProtected())
return CBM::ErrWriteProtectOn;
// check availability and validity of source file name(s).
const QStringList sourceList(paramList[1].split(QChar(',')));
foreach(const QString& srcName, sourceList) {
if(srcName.isEmpty())
return CBM::ErrNoFileGiven;
if(isIllegalCBMName(srcName))
return CBM::ErrSyntaxError;
}
// The destination file must NOT already exist.
if(iface.currentFileDriver()->fileExists(destName))
return CBM::ErrFileExists;
Log(FACDOS, info, QString("About to copy file(s): %1 to %2").arg(paramList[1], destName));
// It is up to the specific file system to do the copy and rest of validation for what file type(s) are possible to concatenate.
return iface.currentFileDriver()->copyFiles(sourceList, destName);
} // CopyFiles
CBM::IOErrorMessage SetPosition::process(const QByteArray& params, Interface& iface)
{
Q_UNUSED(params);
Q_UNUSED(iface);
return CBM::ErrNotImplemented;
} // SetPosition
CBM::IOErrorMessage BlockRead::process(const QByteArray& params, Interface& iface)
{
Q_UNUSED(params);
Q_UNUSED(iface);
return CBM::ErrNotImplemented;
} // BlockRead
CBM::IOErrorMessage BlockWrite::process(const QByteArray& params, Interface& iface)
{
Q_UNUSED(params);
Q_UNUSED(iface);
return CBM::ErrNotImplemented;
} // BlockWrite
CBM::IOErrorMessage MemoryRead::process(const QByteArray& params, Interface& iface)
{
Q_UNUSED(params);
Q_UNUSED(iface);
return CBM::ErrNotImplemented;
} // MemoryReadCmd
CBM::IOErrorMessage MemoryWrite::process(const QByteArray& params, Interface& iface)
{
if(params.length() < 3)
return CBM::ErrSyntaxError;
ushort address = ((ushort)params.at(1)) << 8 bitor ((uchar)params.at(0));
ushort length = (uchar)params.at(2);
QByteArray bytes(params.mid(3));
Log(FACDOS, warning, QString("M-W 0x%1:%2").arg(QString::number(address, 16))
.arg(QString::number(length)));
// What to do if the designated length doesn't match with the actual received amount of bytes?
if(bytes.length() not_eq length) {
// resize and don't expect more, temporary solution?
bytes.resize(length);
// TODO: if we fix this, here we need to know that succeeding bytes are meant to be written with M-W.
// and we need to know how many is left and where.
}
// Do the actual memory write.
iface.writeDriveMemory(address, bytes);
return CBM::ErrOK;
} // MemoryWrite
CBM::IOErrorMessage BufferPointer::process(const QByteArray& params, Interface& iface)
{
Q_UNUSED(params);
Q_UNUSED(iface);
return CBM::ErrNotImplemented;
} // BufferPointer
CBM::IOErrorMessage BlockAllocate::process(const QByteArray& params, Interface& iface)
{
Q_UNUSED(params);
Q_UNUSED(iface);
return CBM::ErrNotImplemented;
} // BlockAllocate
CBM::IOErrorMessage BlockFree::process(const QByteArray& params, Interface& iface)
{
Q_UNUSED(params);
Q_UNUSED(iface);
return CBM::ErrNotImplemented;
} // BlockFree
CBM::IOErrorMessage BlockExecute::process(const QByteArray& params, Interface& iface)
{
Q_UNUSED(params);
Q_UNUSED(iface);
return CBM::ErrNotImplemented;
} // BlockExecute
CBM::IOErrorMessage MemoryExecute::process(const QByteArray& params, Interface& iface)
{
Q_UNUSED(params);
Q_UNUSED(iface);
return CBM::ErrNotImplemented;
} // MemoryExecute
CBM::IOErrorMessage VC20ModeOnOff::process(const QByteArray& params, Interface& iface)
{
Q_UNUSED(params);
Q_UNUSED(iface);
return CBM::ErrNotImplemented;
} // VC20ModeOnOff
CBM::IOErrorMessage DeviceAddress::process(const QByteArray& params, Interface& iface)
{
bool status;
int newDriveNum(QString(params).toInt(&status));
// only allow the valid range for this.
if(not status or newDriveNum < 4 or newDriveNum > 30)
return CBM::ErrSyntaxError;
Log(FACDOS, success, QString("Now changing device adress from #%1 to #%2").arg(iface.deviceNumber()).arg(newDriveNum));
iface.setDeviceNumber(newDriveNum);
return CBM::ErrOK;
} // DeviceAddress
// This is totally f'ed up right now. Fix so that it works as sd2iec.
// http://sd2iec.de/cgi-bin/gitweb.cgi?p=sd2iec.git;a=blob_plain;f=README
CBM::IOErrorMessage ChangeDirectory::process(const QByteArray ¶ms, Interface &iface)
{
Log(FACDOS, info, QString("Changing to directory: %1").arg(QString(params)));
return iface.openFile(params);
} // ChangeDirectory
CBM::IOErrorMessage MakeDirectory::process(const QByteArray& params, Interface& iface)
{
Q_UNUSED(params);
Q_UNUSED(iface);
return CBM::ErrNotImplemented;
} // MakeDirectory
CBM::IOErrorMessage RemoveDirectory::process(const QByteArray ¶ms, Interface& iface)
{
Q_UNUSED(params);
Q_UNUSED(iface);
return CBM::ErrNotImplemented;
} // RemoveDirectory
} // namespace CBMDos