libfusefdc: if we have only one basic file on TR-DOS disk, create simple boot for it
[zymosis.git] / src / libfusefdc / diskfs_trdos.c
bloba90e15f38b756a3cd5fa034bd0be3e15d3ed3f5f
1 /*
2 * TR-DOS filesystem API
3 * Copyright (c) 2020-2022 Ketmar Dark
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is furnished
10 * to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in all
13 * copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
17 * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
18 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
20 * THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 * coded by Ketmar // Invisible Vector
24 * Understanding is not required. Only obedience.
26 #include "diskfs_trdos.h"
27 #include "diskfs_p3dos.h"
29 #include <string.h>
32 //==========================================================================
34 // flpIsValidDisk
36 //==========================================================================
37 int flpIsValidDisk (const disk_t *dsk) {
38 return
39 dsk && dsk->data &&
40 (dsk->sides == 1 || dsk->sides == 2) &&
41 (dsk->cylinders >= 40 && dsk->cylinders <= 83) &&
42 dsk->bpt >= 1024 /*&&
43 dsk->density*/;
47 //==========================================================================
49 // flpDetectDiskType
51 //==========================================================================
52 FloppyDiskType flpDetectDiskType (disk_t *flp) {
53 if (flpIsValidDisk(flp)) {
54 if (flpIsDiskTRDOS(flp)) return FLP_DISK_TYPE_TRDOS;
55 if (flpIsDiskP3DOS(flp)) return FLP_DISK_TYPE_P3DOS;
57 return FLP_DISK_TYPE_UNKNOWN;
61 //**************************************************************************
63 // TR-DOS low level API
65 //**************************************************************************
68 //==========================================================================
70 // flpGetSectorData
72 // <0: error
73 // performs some sanity check
74 // will copy partial sector data (and return -3 aka FLPERR_NOSPACE)
75 // cannot be used to put data to more than one sector
77 //==========================================================================
78 int flpGetSectorData (disk_t *flp, uint8_t tr, uint8_t sc, void *buf, size_t len) {
79 if (!flpIsValidDisk(flp)) return FLPERR_SHIT;
80 int ssize = 0;
81 return (disk_read_sector(flp, tr, sc, buf, len, &ssize) == DISK_OK ? FLPERR_OK : FLPERR_SHIT);
85 //==========================================================================
87 // flpGetSectorDataEx
89 // returns sector size, or negative on error
91 //==========================================================================
92 int flpGetSectorDataEx (disk_t *flp, uint8_t tr, uint8_t sc, void *buf, size_t len) {
93 if (!flpIsValidDisk(flp)) return FLPERR_SHIT;
94 int ssize = 0;
95 if (disk_read_sector(flp, tr, sc, buf, len, &ssize) != DISK_OK) return FLPERR_SHIT;
96 return ssize;
100 //==========================================================================
102 // flpGetSectorDataPtrRO
104 //==========================================================================
105 const uint8_t *flpGetSectorDataPtrRO (disk_t *flp, uint8_t tr, uint8_t sc) {
106 if (!flpIsValidDisk(flp)) return NULL;
107 int ssize = 0;
108 return disk_get_sector_data_ptr(flp, tr, sc, &ssize, NULL);
112 //==========================================================================
114 // flpGetSectorDataPtrRW
116 //==========================================================================
117 uint8_t *flpGetSectorDataPtrRW (disk_t *flp, uint8_t tr, uint8_t sc) {
118 if (!flpIsValidDisk(flp)) return NULL;
119 int ssize = 0;
120 return disk_get_sector_data_ptr(flp, tr, sc, &ssize, NULL);
124 //==========================================================================
126 // flpPutSectorData
128 // <0: error
129 // performs some sanity check
130 // will completely reject too long data (no changes will be made, will return -3 aka FLPERR_NOSPACE)
131 // cannot be used to put data to more than one sector
132 // you can use zero `len` (`buf` doesn't matter in this case) to fix data CRC
133 // but it is better to call `flpFixSectorDataCRC()` instead
135 //==========================================================================
136 int flpPutSectorData (disk_t *flp, uint8_t tr, uint8_t sc, const void *buf, size_t len) {
137 if (!flpIsValidDisk(flp)) return FLPERR_SHIT;
138 return (disk_write_sector(flp, tr, sc, buf, len) == DISK_OK ? FLPERR_OK : FLPERR_SHIT);
142 //==========================================================================
144 // flpFixSectorDataCRC
146 //==========================================================================
147 int flpFixSectorDataCRC (disk_t *flp, uint8_t tr, uint8_t sc) {
148 if (!flpIsValidDisk(flp)) return FLPERR_SHIT;
149 return (disk_write_sector(flp, tr, sc, NULL, 0) == DISK_OK ? FLPERR_OK : FLPERR_SHIT);
153 //==========================================================================
155 // flpIsDiskTRDOS
157 //==========================================================================
158 int flpIsDiskTRDOS (disk_t *flp) {
159 if (!flpIsValidDisk(flp)) return 0;
160 // trdos
161 uint8_t fbuf[0x100];
162 if (flpGetSectorData(flp, 0, 15, fbuf, 0x100) != FLPERR_OK) return 0;
163 // at least 16 sectors
164 if (flpGetSectorData(flp, 0, 9, fbuf, 0x100) != FLPERR_OK) return 0;
165 return (fbuf[0xe7] == 0x10u);
169 //==========================================================================
171 // calcHobSum
173 //==========================================================================
174 static uint16_t calcHobSum (const void *hdr) {
175 const uint8_t *buf = (const uint8_t *)hdr;
176 uint16_t res = 0;
177 for (unsigned int f = 0; f < 15; ++f) res += ((uint16_t)buf[f])*257+f;
178 return res;
182 //==========================================================================
184 // flpIsHoBetaBuf
186 //==========================================================================
187 int flpIsHoBetaBuf (const void *buf, int size) {
188 const uint8_t *b = (const uint8_t *)buf;
189 if (size < 17 || ((size-17)&0xff)) return 0;
190 uint16_t csum = calcHobSum(buf);
191 if ((csum&0xff) != b[15] || ((csum&0xff00)>>8) != b[16]) return 0;
192 return 1;
196 //==========================================================================
198 // flpLoadHoBeta
200 //==========================================================================
201 int flpLoadHoBeta (disk_t *flp, FILE *fl) {
202 uint8_t secBuf[256];
203 TRFile nfle;
204 uint16_t csum;
205 if (fl == NULL) return FLPERR_SHIT;
206 if (!flpIsValidDisk(flp)) return FLPERR_SHIT;
207 if (flpDetectDiskType(flp) != FLP_DISK_TYPE_TRDOS) {
208 libfdcMsg(LIBFDC_MSG_ERROR, "emulated floppy not a TR-DOS disk");
209 return FLPERR_SHIT;
211 if (fread(secBuf, 17, 1, fl) != 1) {
212 libfdcMsg(LIBFDC_MSG_ERROR, "cannot read HoBeta header");
213 return FLPERR_SHIT;
215 csum = calcHobSum(secBuf);
216 if ((csum&0xff) != secBuf[15] || ((csum&0xff00)>>8) != secBuf[16]) {
217 libfdcMsg(LIBFDC_MSG_ERROR, "invalid HoBeta header checksum");
218 fseek(fl, -17, SEEK_CUR);
219 return FLPERR_SHIT;
221 memcpy(&nfle, secBuf, 13);
222 nfle.slen = secBuf[14];
223 if (flpCreateFileTRD(flp, &nfle) != FLPERR_OK) {
224 libfdcMsg(LIBFDC_MSG_ERROR, "cannot create file on TR-DOS disk");
225 return FLPERR_SHIT;
227 for (int i = 0; i < nfle.slen; ++i) {
228 if (fread(secBuf, 256, 1, fl) != 1) {
229 libfdcMsg(LIBFDC_MSG_ERROR, "cannot read HoBeta data");
230 return FLPERR_SHIT;
232 if (flpPutSectorData(flp, nfle.trk, nfle.sec+1, secBuf, 256) != FLPERR_OK) {
233 libfdcMsg(LIBFDC_MSG_ERROR, "cannot write HoBeta data to TR-DOS disk");
234 return FLPERR_SHIT;
236 ++nfle.sec;
237 if (nfle.sec > 15) {
238 ++nfle.trk;
239 nfle.sec -= 16;
242 flp->dirty = 1;
243 return FLPERR_OK;
247 //==========================================================================
249 // flpSaveHoBeta
251 //==========================================================================
252 int flpSaveHoBeta (disk_t *flp, FILE *fl, int catidx) {
253 uint8_t buf[256]; // header/sector
254 uint16_t csum;
255 TRFile tfl;
256 uint8_t tr, sc;
257 if (fl == NULL) return FLPERR_SHIT;
258 if (!flpIsValidDisk(flp)) return FLPERR_SHIT;
259 if (flpGetDirEntryTRD(flp, &tfl, catidx) != FLPERR_OK) return FLPERR_SHIT;
260 memcpy(buf, tfl.name, 13);
261 buf[13] = 0x00;
262 buf[14] = tfl.slen;
263 csum = calcHobSum(buf);
264 buf[15] = (csum&0xff);
265 buf[16] = ((csum&0xff00)>>8);
266 if (fwrite(buf, 17, 1, fl) != 1) return FLPERR_SHIT;
267 tr = tfl.trk;
268 sc = tfl.sec;
269 for (unsigned int f = 0; f < tfl.slen; ++f) {
270 if (flpGetSectorData(flp, tr, sc+1, buf, 256) != FLPERR_OK) return FLPERR_SHIT;
271 if (fwrite(buf, 256, 1, fl) != 1) return FLPERR_SHIT;
272 if (++sc > 15) { ++tr; sc = 0; }
274 return FLPERR_OK;
278 //==========================================================================
280 // flpFormatTRD
282 // format whole disk as 2x84x16x256 and init as TRDOS
284 //==========================================================================
285 int flpFormatTRD (disk_t *flp) {
286 if (!flp) return FLPERR_SHIT;
288 int dres = disk_new(flp, 2, 80, DISK_DD, DISK_TRD);
289 if (dres != DISK_OK) {
290 libfdcMsg(LIBFDC_MSG_ERROR, "cannot create disk: %s", disk_strerror(dres));
291 return FLPERR_SHIT;
294 if (disk_format(flp, 2, 80, 1, 16, 256, 2) != DISK_OK) return FLPERR_SHIT;
296 // first track
297 const uint8_t trd_8e0[32] = {
298 0x00,0x00,0x01,0x16,0x00,0xf0,0x09,0x10,0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,
299 0x20,0x20,0x20,0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x00,0x00,
302 uint8_t buf[256];
303 memset(buf, 0, sizeof(buf));
304 memcpy(buf+(0x8e0%256), trd_8e0, 32);
306 dres = disk_write_sector(flp, 0, 9, buf, 256);
307 if (dres != DISK_OK) {
308 libfdcMsg(LIBFDC_MSG_ERROR, "cannot write directory: %s", disk_strerror(dres));
309 return FLPERR_SHIT;
312 return FLPERR_OK;
317 //**************************************************************************
319 // TR-DOS utilities
321 //**************************************************************************
323 //==========================================================================
325 // flpCreateFileTRD
327 //==========================================================================
328 int flpCreateFileTRD (disk_t *flp, TRFile *dsc) {
329 if (flpDetectDiskType(flp) != FLP_DISK_TYPE_TRDOS) return FLPERR_SHIT;
330 uint8_t fbuf[0x100];
331 uint8_t files;
332 uint16_t freesec;
333 if (flpGetSectorData(flp, 0, 9, fbuf, 256) != FLPERR_OK) return FLPERR_SHIT;
334 dsc->sec = fbuf[0xe1];
335 dsc->trk = fbuf[0xe2];
336 files = fbuf[0xe4];
337 if (files > FLP_TRDOS_DIRCOUNT_MAX) return FLPERR_MANYFILES;
338 ++files;
339 fbuf[0xe4] = files;
340 freesec = fbuf[0xe5]+(fbuf[0xe6]<<8);
341 if (freesec < dsc->slen) return FLPERR_NOSPACE;
342 freesec -= dsc->slen;
343 fbuf[0xe5] = (freesec&0xff);
344 fbuf[0xe6] = ((freesec&0xff00)>>8);
345 fbuf[0xe1] += (dsc->slen&0x0f);
346 fbuf[0xe2] += ((dsc->slen&0xf0)>>4);
347 if (fbuf[0xe1] > 0x0f) {
348 fbuf[0xe1] -= 0x10;
349 ++fbuf[0xe2];
351 if (flpPutSectorData(flp, 0, 9, fbuf, 256) != FLPERR_OK) return FLPERR_SHIT;
352 freesec = ((files&0xf0)>>4)+1;
353 if (flpGetSectorData(flp, 0, freesec, fbuf, 256) != FLPERR_OK) return FLPERR_SHIT;
354 memmove(fbuf+(((files-1)&0x0f)<<4), dsc, 16);
355 flpPutSectorData(flp, 0, freesec, fbuf, 256);
356 flp->dirty = 1;
357 return FLPERR_OK;
361 //==========================================================================
363 // flpDeleteFileTRD
365 //==========================================================================
366 int flpDeleteFileTRD (disk_t *flp, int num) {
367 if (num < 0 || num >= FLP_TRDOS_DIRCOUNT_MAX) return FLPERR_SHIT;
368 if (flpDetectDiskType(flp) != FLP_DISK_TYPE_TRDOS) return FLPERR_SHIT;
369 uint8_t fbuf[0x100];
370 if (flpGetSectorData(flp, 0, 9, fbuf, 256) != FLPERR_OK) return FLPERR_SHIT;
371 uint8_t files = fbuf[0xe4];
372 if (files == 0 || num >= files) return FLPERR_MANYFILES;
373 const int sec = ((num&0xf0)>>4)+1; // sector
374 const int pos = ((num&0x0f)<<4); // file number inside sector
375 uint8_t markByte = 0x01;
376 if (num == files-1) {
377 --fbuf[0xe4]; // decrement number of files
378 if (flpPutSectorData(flp, 0, 9, fbuf, 256) != FLPERR_OK) return FLPERR_NOSPACE;
379 // load directory sector
380 if (flpGetSectorData(flp, 0, sec, fbuf, 256) != FLPERR_OK) return FLPERR_NOSPACE;
381 // this file is no more, and shorten the directory too
382 markByte = 0x00;
384 // load directory sector
385 if (flpGetSectorData(flp, 0, sec, fbuf, 256) != FLPERR_OK) return FLPERR_NOSPACE;
386 if (fbuf[pos] != markByte) {
387 fbuf[pos] = markByte;
388 if (flpPutSectorData(flp, 0, sec, fbuf, 256) != FLPERR_OK) return FLPERR_NOSPACE;
390 return FLPERR_OK;
394 //==========================================================================
396 // flpGetDirEntryTRD
398 //==========================================================================
399 int flpGetDirEntryTRD (disk_t *flp, TRFile *dst, int num) {
400 uint8_t fbuf[0x100];
401 int sec, pos;
402 if (flpDetectDiskType(flp) != FLP_DISK_TYPE_TRDOS) return FLPERR_SHIT;
403 if (num < 0 || num > FLP_TRDOS_DIRCOUNT_MAX) return FLPERR_MANYFILES;
404 sec = ((num&0xf0)>>4); // sector
405 pos = ((num&0x0f)<<4); // file number inside sector
406 if (flpGetSectorData(flp, 0, sec+1, fbuf, 256) != FLPERR_OK) return FLPERR_NOSPACE;
407 if (dst != NULL) memmove(dst, fbuf+pos, 16);
408 return FLPERR_OK;
412 //==========================================================================
414 // flpGetDirectoryTRD
416 //==========================================================================
417 int flpGetDirectoryTRD (disk_t *flp, TRFile *dst) {
418 int cnt = 0;
419 if (flpDetectDiskType(flp) == FLP_DISK_TYPE_TRDOS) {
420 uint8_t *dpt = (uint8_t *)dst;
421 uint8_t fbuf[0x100];
422 for (int sc = 1; sc < 9; ++sc) {
423 if (flpGetSectorData(flp, 0, sc, fbuf, 256) != FLPERR_OK) break;
424 const uint8_t *ptr = fbuf;
425 unsigned fc;
426 for (fc = 0; fc < 16; ++fc) {
427 if (*ptr == 0) break;
428 if (dpt) {
429 memmove(dpt, ptr, 16);
430 dpt += 16;
432 ptr += 16;
433 ++cnt;
435 if (fc < 16) break;
438 return cnt;
443 //**************************************************************************
445 // 'boot' utilities
447 //**************************************************************************
449 int flpIsBootFCBTRD (const TRFile *fcb) {
450 if (!fcb) return 0;
451 return (memcmp(fcb->name, "boot B", 9) == 0);
455 //==========================================================================
457 // flpHasBootTRD
459 //==========================================================================
460 int flpHasBootTRD (disk_t *flp) {
461 if (flpDetectDiskType(flp) == FLP_DISK_TYPE_TRDOS) {
462 TRFile cat[128];
463 int catSize = flpGetDirectoryTRD(flp, cat);
464 for (int i = 0; i < catSize; ++i) {
465 if (flpIsBootFCBTRD(&cat[i])) return i;
468 return FLPERR_SHIT;
472 //==========================================================================
474 // flpSetBootTRD
476 //==========================================================================
477 int flpSetBootTRD (disk_t *flp, FILE *fl, int replace) {
478 if (flpDetectDiskType(flp) == FLP_DISK_TYPE_TRDOS) {
479 int idx = flpHasBootTRD(flp);
480 if (idx >= 0) {
481 if (!replace) return FLPERR_OK;
482 if (flpDeleteFileTRD(flp, idx) != FLPERR_OK) return FLPERR_SHIT;
484 return flpLoadHoBeta(flp, fl);
486 return FLPERR_SHIT;
490 //==========================================================================
492 // flpFindFirstBasicTRD
494 //==========================================================================
495 int flpFindFirstBasicTRD (disk_t *flp, TRFile *dst, int ffirst) {
496 if (flpDetectDiskType(flp) != FLP_DISK_TYPE_TRDOS) return FLPERR_SHIT;
497 if (ffirst < 0) ffirst = 0;
498 TRFile fcb;
499 for (; ffirst < FLP_TRDOS_DIRCOUNT_MAX; ++ffirst) {
500 if (flpGetDirEntryTRD(flp, &fcb, ffirst) != 0) break;
501 if (fcb.name[0] == 0) break; // end of directory
502 if (fcb.name[0] == 1) continue; // deleted
503 if (fcb.ext != 'B') continue;
504 int nameok = 1;
505 int seennonspc = 0;
506 for (unsigned f = 0; f < 8; ++f) {
507 const uint8_t ch = (unsigned)(fcb.name[f]&0xffU);
508 if (ch < 32 || ch == '"') { nameok = 0; break; }
509 if (ch != 32) seennonspc = 1;
511 if (!nameok || !seennonspc) continue;
512 if (dst) memcpy(dst, &fcb, sizeof(TRFile));
513 return ffirst;
515 return FLPERR_SHIT;
519 //==========================================================================
521 // isGoodBasicName
523 //==========================================================================
524 static int isGoodBasicName (const TRFile *fcb) {
525 if (!fcb) return 0;
526 if (fcb->ext != 'B') return 0;
527 if (fcb->name[0] <= 32 || fcb->name[0] >= 127) return 0;
528 for (int f = 0; f < 8; ++f) {
529 if (fcb->name[f] >= 'A' && fcb->name[f] <= 'Z') return 1;
530 //if (fcb->name[f] >= 'a' && fcb->name[f] <= 'z') return 1;
531 if (fcb->name[f] >= '0' && fcb->name[f] <= '9') continue;
532 if (fcb->name[f] == ' ') continue;
533 return 0;
535 return 0;
539 //==========================================================================
541 // flpHasAnyNonBootBasicNonBootTRD
543 //==========================================================================
544 int flpHasAnyNonBootBasicNonBootTRD (disk_t *flp, TRFile *dst) {
545 if (flpDetectDiskType(flp) != FLP_DISK_TYPE_TRDOS) return 0;
546 // check if we have any non-boot basic file
547 TRFile fcb;
548 int seenAllBasic = 0;
549 int fidx = 0;
550 for (;;) {
551 fidx = flpFindFirstBasicTRD(flp, &fcb, fidx);
552 if (fidx < 0) break;
553 ++fidx;
554 if (flpIsBootFCBTRD(&fcb)) return 0;
555 if (!isGoodBasicName(&fcb)) {
556 if (fcb.ext == 'B') ++seenAllBasic;
557 continue;
559 if (dst) memcpy(dst, &fcb, sizeof(TRFile));
560 return 1;
562 return (seenAllBasic == 1);
566 //==========================================================================
568 // flpSetBootSimpleTRD
570 //==========================================================================
571 int flpSetBootSimpleTRD (disk_t *flp) {
572 if (flpDetectDiskType(flp) != FLP_DISK_TYPE_TRDOS) return FLPERR_SHIT;
574 // check if we have any non-boot basic file
575 TRFile fcbbas;
576 int fidx = 0;
577 int seenBasic = 0;
578 int seenAllBasic = 0;
579 for (;;) {
580 TRFile fcb;
581 fidx = flpFindFirstBasicTRD(flp, &fcb, fidx);
582 if (fidx < 0) break;
583 if (flpIsBootFCBTRD(&fcb)) return FLPERR_SHIT; // nothing to do
584 //fprintf(stderr, "...: <%.8s : %c> : %d\n", fcb.name, fcb.ext, isGoodBasicName(&fcb));
585 if (fcb.ext == 'B') ++seenAllBasic;
586 if (isGoodBasicName(&fcb)) {
587 if (seenBasic) return FLPERR_SHIT; // too many basic files
588 seenBasic = 1;
589 memcpy(&fcbbas, &fcb, sizeof(fcbbas));
591 ++fidx;
594 if (!(seenBasic || seenAllBasic == 1)) return FLPERR_SHIT;
596 if (!seenBasic) {
597 if (seenAllBasic != 1) return FLPERR_SHIT; // just in case
598 fidx = 0;
599 for (;;) {
600 TRFile fcb;
601 fidx = flpFindFirstBasicTRD(flp, &fcb, fidx);
602 if (fidx < 0) break;
603 if (fcb.ext == 'B') {
604 memcpy(&fcbbas, &fcb, sizeof(fcbbas));
605 break;
607 ++fidx;
609 if (fidx < 0) return FLPERR_SHIT;
612 // create simple autorun boot:
613 // 10 RANDOMIZE USR VAL "15619":REM RUN "file"
615 uint8_t secBuf[256];
616 memset(secBuf, 0, sizeof(secBuf));
617 size_t scpos = 0;
618 // line number
619 secBuf[scpos++] = 0;
620 secBuf[scpos++] = 10;
621 // line size (will be fixed later)
622 secBuf[scpos++] = 0;
623 secBuf[scpos++] = 0;
624 // line data
625 secBuf[scpos++] = 0xf9U; // RANDOMIZE
626 secBuf[scpos++] = 0xc0U; // USR
627 secBuf[scpos++] = 0xb0U; // VAL
628 secBuf[scpos++] = '"';
629 secBuf[scpos++] = '1';
630 secBuf[scpos++] = '5';
631 secBuf[scpos++] = '6';
632 secBuf[scpos++] = '1';
633 secBuf[scpos++] = '9';
634 secBuf[scpos++] = '"';
635 secBuf[scpos++] = ':';
636 secBuf[scpos++] = 0xeaU; // REM
637 secBuf[scpos++] = ':';
638 secBuf[scpos++] = 0xf7U; // RUN // 0xefU; // LOAD
639 secBuf[scpos++] = '"';
640 // put name
641 size_t nlen = 8;
642 while (nlen > 0 && fcbbas.name[nlen-1] == ' ') --nlen;
643 if (nlen == 0) return FLPERR_SHIT; // just in case
644 memcpy(secBuf+scpos, fcbbas.name, nlen); scpos += nlen;
645 secBuf[scpos++] = '"';
646 // line end
647 secBuf[scpos++] = 13;
648 // fix line size
649 secBuf[2] = (scpos-4)&0xffU;
650 secBuf[3] = ((scpos-4)>>8)&0xffU;
651 // TR-DOS signature
652 secBuf[scpos++] = 0x80;
653 secBuf[scpos++] = 0xaa;
654 // start line
655 secBuf[scpos++] = 10;
656 secBuf[scpos++] = 0;
658 memcpy(fcbbas.name, "boot ", 8);
659 fcbbas.ext = 'B';
660 // last 4 bytes are not in length
661 fcbbas.lst = (scpos-4)&0xff;
662 fcbbas.hst = ((scpos-4)>>8)&0xff;
663 fcbbas.llen = (scpos-4)&0xff;
664 fcbbas.hlen = ((scpos-4)>>8)&0xff;
665 fcbbas.slen = 1; // one sector
666 fcbbas.sec = fcbbas.trk = 0; // will be set in `flpCreateFileTRD()`
668 if (flpCreateFileTRD(flp, &fcbbas) != FLPERR_OK) return FLPERR_SHIT;
669 if (flpPutSectorData(flp, fcbbas.trk, fcbbas.sec+1, secBuf, 256) != FLPERR_OK) return FLPERR_SHIT;
671 flp->dirty = 1;
672 return FLPERR_OK;
676 //==========================================================================
678 // flpRemoveBootTRD
680 // TODO
682 //==========================================================================
683 int flpRemoveBootTRD (disk_t *flp) {
684 if (flpDetectDiskType(flp) != FLP_DISK_TYPE_TRDOS) return FLPERR_SHIT;
685 // find boot
686 TRFile fcb;
687 int fidx = 0;
688 for (;;) {
689 fidx = flpFindFirstBasicTRD(flp, &fcb, fidx);
690 if (fidx < 0) break;
691 if (flpIsBootFCBTRD(&fcb)) {
692 if (flpDeleteFileTRD(flp, fidx) != FLPERR_OK) return FLPERR_SHIT;
694 ++fidx;
696 return FLPERR_SHIT; //TODO