1 /* <<<<Last Modified: Thu Feb 08 15:08:10 1996>>>>
2 ------------------------------------------------------------------------------
3
4 =====
5 CPCfs -- f s . c -- Manageing the Filesystem
6 =====
7
8 Version 0.85 (c) February '96 by Derik van Zuetphen
9 ------------------------------------------------------------------------------
10 */
11
12 #include <stdio.h>
13 #include <string.h>
14 #include <unistd.h>
15 #include <stdlib.h>
16 #ifdef __EMSCRIPTEN__
17 #include <ctype.h>
18 #endif
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 #include <fcntl.h>
22 #include <ctype.h>
23 #include <zlib.h>
24 #include "fs.h"
25
26 #include "cpc_cat.h"
27
28 int cpc_dsk_num_entry = 0;
29 int cpc_dsk_type = 0;
30 char cpc_dsk_dirent[CPC_MAX_ENTRY][CPC_NAME_SIZE];
31
32 /****** Variables ******/
33 uchar *blk_alloc = NULL; /* Block-Allocation-Table, */
34 struct d_header disk_header;
35 DPB_list_entry *dpb_list_entry = NULL;
36 DPB_type *dpb = NULL; /* pointer to current DPB */
37 DPB_list dpb_list;
38 int BLKNR_SIZE = 1;
39 int BLKNR = 16;
40
41 int cur_trk = -1; /* flag for no track loaded */
42 int cur_hd = -1;
43 int cur_blk = -1;
44 /* KT - added directory dirty flag - directory is written only if it has changed! */
45 int directory_dirty = 0;
46 /* KT - added track dirty flag - track is written only if it has changed! */
47 int track_dirty = 0;
48 uchar *track = NULL; /* 0x100 header + track data */
49 unsigned char filler; /* copied from track header */
50 DirEntry *directory = (DirEntry*)NULL;
51 uchar *block_buffer = NULL; /* Buffer for 1024 or more bytes */
52 static int imagefile = -1; /* ... handle of imagefile */
53 static gzFile gz_imagefile = 0;
54 static int gz_format = 0;
55
56 int image_type = 0;
57
my_open(const char * name)58 static int my_open(const char* name)
59 {
60 char *scan = strrchr(name, '.');
61 gz_format = 0;
62 if (scan && (!strcasecmp(scan, ".dsz")))
63 gz_format = 1;
64
65 if (gz_format)
66 {
67 gz_imagefile = gzopen(name, "rb+");
68 if (! gz_imagefile) return -1;
69 }
70 else
71 {
72 int fmode = O_RDONLY;
73 #ifdef _WIN32
74 fmode |=O_BINARY;
75 #endif
76 imagefile = open(name, fmode);
77 if (imagefile < 0) return -1;
78 }
79 return 0;
80 }
81
my_close(void)82 static int my_close(void)
83 {
84 int ret_val = 0;
85 if (gz_format)
86 {
87 if (gz_imagefile)
88 {
89 ret_val = gzclose(gz_imagefile);
90 gz_imagefile = 0;
91 }
92
93 }
94 else
95 {
96 if (imagefile >= 0)
97 {
98 ret_val = close(imagefile);
99 imagefile = -1;
100 }
101 }
102 return ret_val;
103 }
104
my_read(uchar * a_ptr,size_t a_size)105 static int my_read(uchar* a_ptr, size_t a_size)
106 {
107 if (gz_format)
108 return gzread( gz_imagefile, a_ptr, a_size);
109 return read(imagefile, a_ptr, a_size);
110 }
111
my_lseek(long offs,int whence)112 static int my_lseek(long offs, int whence)
113 {
114 if (gz_format)
115 return gzseek( gz_imagefile, offs, whence);
116 return lseek(imagefile, offs, whence);
117 }
118
119
120
build_cpm_name_32(char * buf,int user,char * root,char * ext)121 void build_cpm_name_32(char *buf, int user, char *root, char *ext) {
122 /* ^^^^^^^^^^^^^^^^^
123 The same function as <build_cpm_name> except, that <root> and <ext> are
124 considered as padded with ' ' (= ASCII 32) (as in <DirEntry>)
125 */
126 int j;
127
128 *buf = 0;
129 if (user==-2) {strcpy(buf,"*:"); buf +=2;}
130 if (user>=0) buf += sprintf(buf,"%d:",user);
131
132 memcpy(buf,root,8);
133 j=7; while (buf[j] == ' ') {j--;}; j++;
134 buf[j]='.'; j++;
135 if (strncmp(ext," ",3)!=0) {
136 memcpy(&buf[j],ext,3); j+=2;
137 while (buf[j] == ' ') {j--;}; j++;
138 }
139 buf[j]=0;
140 }
141
142
tag_ok()143 bool tag_ok () {
144 /* ^^^^^^ */
145
146 /* KT - 27/04/2000 - Support for Extended disk image */
147 if (strncmp("EXTENDED", (char *)disk_header.tag,8)==0)
148 {
149 image_type = 1;
150 return TRUE;
151 }
152 else
153 if (strncmp("MV - CPC",(char*)disk_header.tag,8)==0)
154 {
155 image_type = 0;
156 return TRUE;
157 }
158
159 return FALSE;
160 }
161
alloc_block(int blk)162 void alloc_block(int blk) {
163 /* ^^^^^^^^^^^ */
164
165 unsigned long blk_byte_offset;
166 unsigned long blk_bit_offset;
167
168 /* KT - if a disc was opened and the format was not detected correctly, then
169 a invalid blk could be passed to this routine. Previously this attempted
170 to read off the end of the array and cause an error. I've added this check
171 to stop that from occuring and alerting this fact to the user */
172 if ((blk<0) || (blk>=(dpb->DSM+1)))
173 {
174 /* invalid block */
175 return;
176 }
177
178 blk_byte_offset = blk>>3;
179 blk_bit_offset = blk & 0x07;
180
181 blk_alloc[blk_byte_offset]|=(1<<blk_bit_offset);
182 }
183
184
185
186
free_block(int blk)187 void free_block(int blk) {
188 /* ^^^^^^^^^^ */
189
190 unsigned long blk_byte_offset;
191 unsigned long blk_bit_offset;
192
193 if ((blk<0) || (blk>=(dpb->DSM+1)))
194 {
195 /* invalid block */
196 return;
197 }
198
199 blk_byte_offset = blk>>3;
200 blk_bit_offset = blk & 0x07;
201
202 blk_alloc[blk_byte_offset]&=~(1<<blk_bit_offset);
203 }
204
205
is_free_block(int blk)206 bool is_free_block(int blk) {
207 /* ^^^^^^^^^^^^^ */
208
209 unsigned long blk_byte_offset;
210 unsigned long blk_bit_offset;
211
212 if ((blk<0) || (blk>=(dpb->DSM+1)))
213 {
214 /* invalid block */
215 return FALSE;
216 }
217
218 blk_byte_offset = blk>>3;
219 blk_bit_offset = blk & 0x07;
220
221 return (bool)((blk_alloc[blk_byte_offset]&(1<<blk_bit_offset))==0);
222 }
223
224
225 /* KT - added support for different block orders */
calc_t_s_h(int blk,int * track,int * sector,int * head)226 void calc_t_s_h(int blk,int *track, int *sector, int *head)
227 {
228 int t,s,h;
229
230 unsigned long byte_offset;
231 unsigned long sector_offset;
232
233 t = -1;
234 s = -1;
235 h = -1;
236
237 /* calc byte offset from block index and bytes per block */
238 byte_offset = blk*dpb->BLS;
239 /* calc sector offset using sector size */
240 sector_offset = byte_offset/dpb->BPS;
241
242 /* calculate sector index within track by taking remainder after dividing by number of sectors
243 per track (0-dpb->SECS). Sector ID is added on when sector is accessed! */
244 s = sector_offset % dpb->SECS;
245
246 /* calculate track offset by dividing by number of sectors */
247 t = (sector_offset / dpb->SECS) + dpb->OFS;
248
249 /* order system for blocks */
250 switch (dpb->order)
251 {
252 /* track 0 side 0, track 1 side 0... track n side 0, track n side 1, track n-1 side 1 ... track 0 side 1 */
253 case ORDER_CYLINDERS:
254 {
255 /* calc side */
256 h = t/dpb->TRKS;
257
258 /* odd side */
259 if (h & 1)
260 {
261 /* tracks in reverse */
262 t = dpb->TRKS - (t % dpb->TRKS);
263 }
264 else
265 {
266 /* tracks in order */
267 t = t % dpb->TRKS;
268 }
269 }
270 break;
271
272 /* track 0 side 0, track 0 side 1, track 1 side 0, track 1 side 1... track n side 0, track n side 1*/
273 case ORDER_SIDES:
274 {
275 /* calc side */
276 h = t % dpb->HDS;
277 /* calc track */
278 t = t/dpb->HDS;
279 }
280 break;
281
282 /* track 0 side 0, track 1 side 0... track n side 0, track 0 side 1, track 1 side 1....track n side 1 */
283 case ORDER_EAGLE:
284 {
285 /* calc side */
286 h = t / dpb->TRKS;
287
288 /* calc track */
289 t = t % dpb->TRKS;
290 }
291 break;
292 }
293 *track = t;
294 *sector = s;
295 *head = h;
296 }
297
298
299 #if 0
300 /* Calculate track, sector, and head number of the first sector of block
301 <blk>.
302
303 A quick picture:
304
305 secs
306 .------^-------.
307 _______________
308 / -2- - - - - >/| } heads
309 /______________/ | }
310 / | -1- - - - - > | |
311 : | | |
312 : | | |
313 : | | |
314 trks = | -4- - - - - -| |
315 : | | |
316 : | -3- - - - - > | |
317 : | | |
318 \ |_______________|/
319
320
321 numbering scheme:
322 first secs, then heads, then tracks
323 %s /s%h /s/h%t has to be applied on running sec number
324
325 s = sec/trk, h = heads, t = tracks (here infinite)
326
327 */
328
329
330 int trk_calc(int blk) {
331 /* ^^^^^^^^ */
332 return ((long)blk*dpb->BLS/dpb->BPS + dpb->OFS*dpb->SECS)
333 / (dpb->SECS*dpb->HDS);
334 }
335
336 int sec_calc(int blk) {
337 /* ^^^^^^^^
338 The returned number is not shifted by <sec_offset>! */
339 return ((long)blk*dpb->BLS/dpb->BPS + dpb->OFS*dpb->SECS) % dpb->SECS;
340 }
341
342 int hd_calc(int blk) {
343 /* ^^^^^^^ */
344 return ((long)blk*dpb->BLS/dpb->BPS + dpb->OFS*dpb->SECS)
345 / dpb->SECS % dpb->HDS;
346 }
347 #endif
348
349
350 /* TO BE FIXED ! */
351
blk_calc(int hd,int trk,int sec)352 int blk_calc(int hd, int trk, int sec) {
353 /* ^^^^^^^^
354 Return the blocknumber of position <hd>, <trk>, <sec> or -1, if it is a
355 reserved position
356 */
357 #if 0
358 switch (dpb->order)
359 {
360 /* track 0 side 0, track 1 side 0... track n side 0, track n side 1, track n-1 side 1 ... track 0 side 1 */
361 case ORDER_CYLINDERS:
362 {
363
364
365
366 }
367 break;
368
369 case ORDER_EAGLE:
370 {
371
372 }
373 break;
374
375 case ORDER_SIDES:
376 {
377
378
379
380 }
381 break;
382 }
383 #endif
384
385 if (trk*dpb->HDS+hd < dpb->OFS) return -1;
386 return ((long)sec + hd*dpb->SECS
387 + trk*dpb->SECS*dpb->HDS
388 - dpb->OFS*dpb->SECS)
389 / (dpb->BLS/dpb->BPS);
390 }
391
392 /* KT - added common free data function */
free_image_data(void)393 void free_image_data(void)
394 {
395 if (blk_alloc)
396 {
397 free(blk_alloc); blk_alloc=NULL;
398 }
399
400 if (track)
401 {
402 free(track); track=NULL;
403 }
404
405 if (directory)
406 {
407 free(directory); directory=(DirEntry*)NULL;
408 }
409
410 if (block_buffer)
411 {
412 free(block_buffer); block_buffer=(uchar*)NULL;
413 }
414
415 *disk_header.tag = 0;
416 dpb = NULL;
417
418 my_close();
419
420 cur_trk = -1;
421 cur_blk = -1;
422 directory_dirty = 0;
423 }
424
425
426
abandonimage()427 void abandonimage()
428 {
429 free_image_data();
430 }
431
432
433 /********
434 Tracks
435 ********/
436
437 /* KT - get offset to track data. */
get_track_offset(int track,int side)438 unsigned long get_track_offset(int track, int side)
439 {
440 switch (image_type)
441 {
442 /* standard disk image */
443 case 0:
444 {
445 /* attempt to access a invalid track and side */
446 if ((track>=disk_header.nbof_tracks) || (side>=disk_header.nbof_heads))
447 return 0;
448
449 return (((track*disk_header.nbof_heads) + side) * disk_header.tracksize) + 0x0100;
450 }
451 /* extended disk image */
452 case 1:
453 {
454 int i;
455 unsigned long offset;
456
457 /* attempt to access a invalid track and side */
458 if ((track>=disk_header.nbof_tracks) || (side>=disk_header.nbof_heads))
459 return 0;
460
461 /* unformatted track? */
462 if (disk_header.unused[((track*disk_header.nbof_heads)+side)]==0)
463 return 0;
464
465 /* for extended disk image, the disk header contains
466 size of each track / 256. Use this table to calculate
467 the offset to the track */
468
469 offset = 0;
470
471 for (i=0; i<(track*disk_header.nbof_heads)+side; i++)
472 {
473 offset += (disk_header.unused[i]<<8);
474 }
475
476 return offset + 0x0100;
477 }
478
479 default:
480 break;
481 }
482
483 return 0;
484 }
485
get_track_size(int track,int side)486 unsigned long get_track_size(int track, int side)
487 {
488 switch (image_type)
489 {
490 /* standard disk image */
491 case 0:
492 {
493 /* attempt to access a invalid track and side */
494 if ((track>=disk_header.nbof_tracks) || (side>=disk_header.nbof_heads))
495 return 0;
496
497 /* return size of track */
498 return disk_header.tracksize;
499 }
500
501 /* extended disk image */
502 case 1:
503 {
504 /* attempt to access a invalid track and side */
505 if ((track>=disk_header.nbof_tracks) || (side>=disk_header.nbof_heads))
506 return 0;
507
508 /* return track size */
509 return ((disk_header.unused[(track*disk_header.nbof_heads)+side])<<8);
510 }
511
512 default:
513 break;
514 }
515
516 return 0;
517 }
518
is_track_header_valid(unsigned char * track)519 int is_track_header_valid(unsigned char *track)
520 {
521 struct t_header *track_header = (struct t_header*)track;
522
523 /* header limited to 29 sectors per track */
524 if (track_header->SPT>29)
525 return 0;
526
527 /* unlikely to have a track where the BPS is 16384 bytes! */
528 if (track_header->BPS>6)
529 return 0;
530
531
532 return 1;
533 }
534
validate_image(void)535 int validate_image(void)
536 {
537 int t,h;
538 /* header is already validated */
539 for (h=0; h<disk_header.nbof_heads; h++)
540 {
541 for (t=0; t<disk_header.nbof_tracks; t++)
542 {
543 int track_offset = get_track_offset(t,h);
544
545 if (track_offset>=0)
546 {
547 int n;
548
549 int track_size;
550
551 track_size =get_track_size(t,h);
552
553 if (track_size!=0)
554 {
555 /* formatted track */
556 n = my_lseek(track_offset,SEEK_SET);
557 if (n == -1L)
558 {
559 return 0;
560 }
561
562 n = my_read(track,track_size);
563 if (n != track_size)
564 {
565 return 0;
566 }
567
568 /* seeked to position ok, and read data */
569
570 /* check track header */
571 if (!is_track_header_valid(track))
572 return 0;
573 }
574 }
575 }
576 }
577
578 return 1;
579
580 }
581
582
583
584 /* calculate the maximum size of a track from the disk image. Use this
585 to allocate a track buffer */
malloc_track()586 void malloc_track()
587 {
588 unsigned long max_track_size;
589
590 max_track_size = 0;
591
592 switch (image_type)
593 {
594 case 0:
595 {
596 max_track_size = disk_header.tracksize;
597 }
598 break;
599
600 case 1:
601 {
602
603 int t,h;
604
605 for (h=0; h<disk_header.nbof_heads; h++)
606 {
607 for (t=0; t<disk_header.nbof_tracks; t++)
608 {
609 int track_size;
610
611 track_size = get_track_size(t,h);
612
613 if ((t==0) && (h==0))
614 {
615 max_track_size = track_size;
616 }
617 else
618 {
619 if (track_size>max_track_size)
620 {
621 max_track_size = track_size;
622 }
623 }
624 }
625 }
626 }
627 break;
628
629 default:
630 break;
631 }
632
633 track = (void *)malloc(max_track_size);
634 }
635
read_track(int hd,int trk)636 int read_track (int hd, int trk)
637 {
638 /* ^^^^^^^^^^ */
639 long n, pos;
640 int track_size;
641
642 if (trk == cur_trk && hd == cur_hd) {
643 return 0;
644 }
645
646 //printf("[rt(%d,%d)] ",hd,trk);
647
648 track_size = get_track_size(trk,hd);
649
650 if (track_size == 0)
651 return -1;
652
653 pos = get_track_offset(trk, hd);
654
655 if (pos==0)
656 return -1;
657
658 n = my_lseek(pos,SEEK_SET);
659 if (n == -1L) {
660 //fprintf(stdout,"Image corrupt! I cannot position on track %d!", trk);
661 abandonimage();
662 return -1;
663 }
664
665 n = my_read(track,track_size);
666 if (n != track_size) {
667 //fprintf(stdout,"Image corrupt! I can only read %ld bytes " "of track %d (instead of %d bytes)!",
668 // n,trk,disk_header.tracksize);
669 abandonimage();
670 return -1;
671 }
672 cur_trk = trk;
673 cur_hd = hd;
674 track_dirty = 0;
675 return 0;
676 }
677
678
679 /* KT - added support for different block orders */
next_sector(int * hd,int * trk,int * sec)680 bool next_sector (int *hd, int *trk, int *sec) {
681 /* ^^^^^^^^^^^
682 Assumes <sec> without offset. Answer TRUE if the <trk> or <hd> is changed. */
683
684 int prev_hd;
685 int prev_trk;
686
687 prev_hd = *hd;
688 prev_trk = *trk;
689
690 switch (dpb->order)
691 {
692 case ORDER_CYLINDERS:
693 {
694 (*sec)++;
695
696 if ((*sec) >= dpb->SECS)
697 {
698 (*sec) -= dpb->SECS;
699
700 if ((*hd) & 1)
701 {
702 (*trk)--;
703
704 if ((*trk)<0)
705 {
706 (*trk) = 1;
707 (*hd)++;
708 }
709 }
710 else
711 {
712 (*trk)++;
713
714 if ((*trk)>dpb->TRKS)
715 {
716 (*trk) = dpb->TRKS-1;
717 (*hd)++;
718 }
719 }
720 }
721 }
722 break;
723
724 case ORDER_SIDES:
725 {
726 (*sec)++;
727 if (*sec >= dpb->SECS)
728 {
729 *sec -= dpb->SECS;
730 (*hd)++;
731 if (*hd >= dpb->HDS)
732 {
733 *hd = 0;
734 (*trk)++;
735 }
736 }
737 }
738 break;
739
740 case ORDER_EAGLE:
741 {
742 (*sec)++;
743
744 if ((*sec) >= dpb->SECS)
745 {
746 (*sec) -= dpb->SECS;
747
748 (*trk)++;
749
750 if ((*trk)>dpb->TRKS)
751 {
752 *trk = 0;
753 (*hd)++;
754 }
755 }
756 }
757 break;
758
759
760 }
761
762 /* if head, track or head and track have changed, then force a write of track */
763 if ((prev_hd!=(*hd)) || (prev_trk!=(*trk)))
764 {
765 return TRUE;
766 }
767
768 return FALSE;
769 }
770
771
772
773 #if 0
774 bool next_sector (int *hd, int *trk, int *sec) {
775 /* ^^^^^^^^^^^
776 Assumes <sec> without offset. Answer TRUE if the <trk> or <hd> is changed. */
777 (*sec)++;
778 if (*sec >= dpb->SECS) {
779 *sec -= dpb->SECS;
780 (*hd)++;
781 if (*hd >= dpb->HDS) {
782 *hd = 0;
783 (*trk)++;
784 }
785 return TRUE;
786 }
787 return FALSE;
788 }
789 #endif
790
791 /* given a sector id, search through sector id's in track header
792 to find the position of the sector in the track. This allows
793 for interleaved sectors */
get_sector_pos_in_track(int r,int h)794 int get_sector_pos_in_track(int r,int h)
795 {
796 struct t_header *track_header = (struct t_header*)track;
797 struct s_info *sector_info = &track_header->sector[0];
798 int i;
799 int spt;
800
801 /* defines number of sector id's stored */
802 spt = track_header->SPT;
803
804 for (i=0; i<spt; i++)
805 {
806 /* match sector id */
807 if (sector_info->sector==r)
808 {
809 /* match head value */
810 if (sector_info->head == h)
811 {
812 return i;
813 }
814 }
815
816 sector_info++;
817 }
818
819 /* sector not found */
820 return -1;
821 }
822
get_sector_data_offset_extended(int pos)823 int get_sector_data_offset_extended(int pos)
824 {
825 struct t_header *track_header = (struct t_header*)track;
826 struct s_info *sector_info = &track_header->sector[0];
827 int i;
828 int sector_offset;
829
830 sector_offset = 0;
831
832 for (i=0; i<pos; i++)
833 {
834 int sector_size;
835
836 sector_size = sector_info->unused[0] +
837 (sector_info->unused[1]<<8);
838
839 sector_info++;
840 sector_offset += sector_size;
841 }
842
843 return sector_offset;
844 }
845
846 /* N value used in formatting and reading/writing data. This defines
847 the amount of data stored in the sector */
get_sector_size_from_n(int n)848 int get_sector_size_from_n(int n)
849 {
850 return (1<<n)<<7;
851 }
852
get_sector_data_ptr(int r,int h)853 uchar *get_sector_data_ptr(int r,int h)
854 {
855 struct t_header *track_header = (struct t_header*)track;
856
857 /* using sector id find sector pos in track */
858 int pos = get_sector_pos_in_track(r,h);
859 int sector_offset = 0;
860
861 if (pos==-1)
862 return NULL;
863
864 switch (image_type)
865 {
866 case 0:
867 {
868 /* for standard disk images, N in the track header should
869 define the largest sector size */
870 int sector_size = get_sector_size_from_n(track_header->BPS);
871
872 sector_offset = 0x0100 + pos*sector_size;
873 }
874 break;
875
876 case 1:
877 sector_offset = 0x0100 + get_sector_data_offset_extended(pos);
878 break;
879
880 default:
881 return NULL;
882 }
883
884 return track+sector_offset;
885 }
886
read_block(int blk)887 uchar *read_block (int blk) {
888 /* ^^^^^^^^^^
889 Read block <blk> into a buffer and return its address, or NULL on error */
890 int trk, sec, hd;
891 int filled = 0;
892 uchar *sector_ptr;
893
894
895 if (blk==cur_blk) return block_buffer;
896
897 if ((blk<0) || (blk>=(dpb->DSM+1)))
898 return NULL;
899
900 //printf("[rb(%d)] ",blk);
901
902 /* trk = trk_calc (blk);
903 sec = sec_calc (blk);
904 hd = hd_calc (blk);*/
905
906 calc_t_s_h(blk, &trk, &sec, &hd);
907
908 while (filled < dpb->BLS)
909 {
910 int r,h;
911
912 if (read_track(hd,trk))
913 return NULL;
914
915 r = sec;
916
917 if (hd==0)
918 {
919 h = dpb->side0_hd;
920 r += dpb->SEC1_side1;
921 }
922 else
923 {
924 h = dpb->side1_hd;
925 r += dpb->SEC1_side2;
926 }
927
928 sector_ptr = get_sector_data_ptr(r,h);
929
930 if (sector_ptr==NULL)
931 {
932 //fprintf(stdout, "Warning: cannot find sector, unable to read data!");
933 return NULL;
934 }
935
936 memcpy(block_buffer+filled, sector_ptr, dpb->BPS);
937
938 filled += dpb->BPS;
939 next_sector (&hd,&trk,&sec);
940 }
941 cur_blk = blk;
942 return block_buffer;
943 }
944
945
946 /***********
947 Directory
948 ***********/
949
950
951 /* local definitions for glob_cpm_* */
952
953 #define GLOB_ENV_MAX 3
954 int glob_env = 0;
955 /* determines which global variable-set should <glob_cpm_*> use, */
956 /* necessary for nested globs */
957
958 /* local definitions for update_directory */
959
960 struct pair {uchar en; uchar ex;};
961
cmp_pair(struct pair * x,struct pair * y)962 int cmp_pair(struct pair *x, struct pair *y) {
963 if (x->ex < y->ex) return -1;
964 if (x->ex > y->ex) return 1;
965 return 0;
966 }
967
update_directory(int set_dirty)968 void update_directory(int set_dirty) {
969 /* ^^^^^^^^^^^^^^^^
970 (Re-)Organizes the directory structure (Packing the name, making a linked
971 list) */
972
973 int i, j;
974
975 /* a dynamic array of (entry,extent) pairs */
976 struct pair *map;
977
978 if (set_dirty)
979 {
980 directory_dirty = 1;
981 }
982
983
984 //printf("[ud] ");
985 map = (struct pair*)malloc(sizeof(DirEntry)*(dpb->DRM+1));
986
987 /* KT - added memory fail check */
988 if (map==NULL)
989 return;
990
991 /****** packing a name of kind "FOO BAR" to "FOO.BAR\0" ******/
992 for (i=0;i<=dpb->DRM;i++) {
993 if (directory[i].user == 0xE5) continue;
994 build_cpm_name_32((char*)directory[i].name, -1,
995 (char*)directory[i].root,
996 (char*)directory[i].ext);
997 }
998
999
1000 /****** organizing the directory structure as linked list ******/
1001
1002 /* set entries in the directory to "not visited"
1003 <size> = 0 : never visit; <size> = -1 : not yet visited */
1004 for (i=0;i<=dpb->DRM;i++) {
1005 if (directory[i].user == 0xE5) /*NOT <filler>, E5 is required*/
1006 directory[i].size = 0; /* never visit empty entries */
1007 else
1008 directory[i].size = -1; /* not visited */
1009 directory[i].first = FALSE;
1010 directory[i].next = -1;
1011 };
1012
1013 /* scan the entries */
1014 for (i=0;i<=dpb->DRM;i++) {
1015 if (directory[i].size > -1) continue;
1016
1017 /* reset the map */
1018 for (j=0;j<=dpb->DRM;j++) {map[j].en=(uchar)j;map[j].ex=(uchar)0xFF;}
1019
1020 /* fill the map with <extent> from the directory */
1021 map[i].ex = directory[i].extent;
1022 for (j=0;j<=dpb->DRM;j++) {
1023 if ((directory[j].size == -1) &&
1024 (directory[j].user == directory[i].user) &&
1025 (i!=j) &&
1026 (strcmp((char*)directory[i].name,
1027 (char*)directory[j].name)==0)) {
1028 map[j].ex = directory[j].extent;
1029 directory[j].size = 0;
1030 }
1031 }
1032 /* sort the map according to map[].ex, not necessary in most cases */
1033 qsort(map,dpb->DRM+1,sizeof(struct pair),
1034 (int(*)(const void*,const void*))cmp_pair);
1035
1036 /* fill <first>, <size> and <next> from the map */
1037 directory[map[0].en].first = TRUE;
1038 j=1;
1039 while (map[j].ex < 0xFF) {
1040 directory[map[j-1].en].next = map[j].en;
1041 j++;
1042 }
1043 directory[map[j-1].en].next = -1;
1044
1045 /* the filesize located in the first fileentry can be calculated from the
1046 <extent> and <rec> fields of the last fileentry */
1047
1048 /* KT: changed calculation to use extent number, and block size */
1049 directory[map[0].en].size =
1050 ((long)directory[map[j-1].en].extent * EXTENTSIZE)
1051 + (directory[map[j-1].en].rec * RECORDSIZE);
1052
1053
1054 } /* for i */
1055
1056 free(map); map=NULL;
1057 }
1058
1059
get_directory()1060 void get_directory()
1061 {
1062 /* ^^^^^^^^^^^^^ */
1063 int i,j,off;
1064 uchar *buf;
1065 int mask;
1066
1067 //printf("[rd] ");
1068 for (i=0; i<=dpb->DRM; i++)
1069 {
1070 directory[i].user = 0x0e5;
1071 }
1072
1073 /* reading the directory data */
1074 for (i=0;i<=dpb->DRM;i++) {
1075 buf = read_block((signed)i*32/dpb->BLS);
1076
1077 if (buf==0)
1078 break;
1079
1080 off = i*32 % dpb->BLS;
1081 /* user, name, ... */
1082 directory[i].user = buf[off+0];
1083 for (j=0;j<8;j++) directory[i].root[j] = (buf[off+j+1] & 0x7F);
1084 for (j=0;j<3;j++) directory[i].ext[j] = (buf[off+j+9] & 0x7F);
1085 directory[i].name[0] = 0;
1086
1087 directory[i].extent = buf[off+12];
1088 directory[i].unused[0] = buf[off+13];
1089 directory[i].unused[1] = buf[off+14];
1090 directory[i].rec = buf[off+15];
1091
1092 /* attributes */
1093 mask=0x1;
1094 directory[i].attr = 0;
1095 for (j=11;j>0;j--) {
1096 if (buf[off+j]&0x80) directory[i].attr |= mask;
1097 mask <<= 1;
1098 }
1099
1100 /* block pointer */
1101 for (j=0;j<16;j++) directory[i].blk[j] = 0;
1102 if (BLKNR_SIZE==1) {
1103 for (j=0;j<16;j++) {
1104 directory[i].blk[j] = buf[off+16+j];
1105 }
1106 } else if (BLKNR_SIZE==2) {
1107 for (j=0;j<8;j++) {
1108 directory[i].blk[j] = (buf[off+16+2*j]
1109 + (buf[off+17+2*j]<<8));
1110 }
1111 }
1112 }
1113
1114 update_directory(0);
1115 /*for (i=0;i<dpb->DBL;i++) alloc_block(i,0);*/ /* 0 is not correct! */
1116
1117 /* marking all blocks as free */
1118 for (j=0;j<=dpb->DSM;j++) free_block(j);
1119
1120 {
1121 /* mark allocated blocks from AL1, AL0 as used */
1122 /* AL0 and AL1 make a bitmask. AL0 is bits 15..8, AL1 is
1123 bits 7..0. If a bit is set, a block is allocated. Block indexs
1124 go from 0-15, bits 15..0 */
1125 unsigned long bit_mask;
1126
1127 bit_mask = (dpb->AL0<<8) | dpb->AL1;
1128
1129 for (i=0; i<16; i++)
1130 {
1131 /* is bit set? */
1132 if (bit_mask & 0x08000)
1133 {
1134 /* yes, alloc block */
1135 alloc_block(i);
1136 }
1137 /* shift for next bit */
1138 bit_mask = bit_mask<<1;
1139
1140 }
1141 }
1142
1143 /* mark blocks used by files as allocated */
1144 cpc_dsk_num_entry = 0;
1145 for (i=0;i<=dpb->DRM;i++)
1146 {
1147 if ((directory[i].user!=0xE5) && (directory[i].first)) {
1148 strncpy((char *)cpc_dsk_dirent[cpc_dsk_num_entry], (char *)directory[i].name, CPC_NAME_SIZE);
1149 cpc_dsk_num_entry++;
1150 if (cpc_dsk_num_entry >= CPC_MAX_ENTRY) break;
1151 }
1152 for (j=0;j<BLKNR;j++)
1153 {
1154 if (directory[i].user!=0xE5)
1155 {
1156 /* KT - changed. will quit out at the first zero block index found */
1157 if (directory[i].blk[j])
1158 {
1159 alloc_block(directory[i].blk[j]);
1160 }
1161 else
1162 break;
1163 }
1164 }
1165 }
1166 }
1167
1168
1169 /*******
1170 Image
1171 *******/
1172
get_bit_count_from_mask(unsigned long mask)1173 int get_bit_count_from_mask(unsigned long mask)
1174 {
1175 int bit_count;
1176
1177 bit_count = 0;
1178
1179 while ((mask & 1)!=0)
1180 {
1181 bit_count++;
1182 mask = mask>>1;
1183 }
1184
1185 return bit_count;
1186 }
1187
1188
1189 /* at this point we should have a format which matches the disk image format */
1190 /* TRKS in DPB is not good. In 22disk this defines the physical disk structure. */
update_dpb(DPB_type * dpb,uchar * track)1191 void update_dpb(DPB_type *dpb, uchar *track) {
1192 /* ^^^^^^^^^^
1193 Determine the extended DPB data out of <dpb> and the sample track <track>.
1194 Complete the extension parts of <dpb>. <track> must be read in first!
1195 */
1196 int BLKNR_MAX;
1197 int sectors_per_dir;
1198
1199 dpb->BLS = 1 << (dpb->BSH + 7); /* or 2^BSH*128 */
1200
1201 /* KT - already present in format description */
1202 #if 0
1203 /* an image must exist, do not call form <format>! */
1204 dpb->SEC1 = ((struct t_header*)track)->sector[0].sector;
1205 dpb->SECS = ((struct t_header*)track)->SPT;
1206
1207 /* KT - Removed because they are already specified */
1208 /* the next two elements should already be set */
1209 dpb->TRKS = disk_header.nbof_tracks;
1210 dpb->HDS = disk_header.nbof_heads;
1211 #endif
1212
1213 dpb->SYS = (dpb->OFS>0) && (*(track+0x100)) != filler;
1214 dpb->DBL = 32 * (dpb->DRM+1) / dpb->BLS; /* or often CKS/8 */
1215
1216 /* KT - Removed because this is already specified */
1217 #if 0
1218 /* DSM will be specified, so no need to calculate */
1219
1220 dpb->DSM = (dpb->TRKS*dpb->HDS*dpb->SECS) / (dpb->BLS/dpb->BPS);
1221 /* subtract reserved tracks */
1222 dpb->DSM -= dpb->OFS * dpb->SECS / (dpb->BLS/dpb->BPS);
1223 dpb->DSM--;
1224 #endif
1225
1226 /* KT - Added because it is no longer stored! */
1227 dpb->SPT = (dpb->SECS*dpb->BPS)/RECORDSIZE;
1228
1229 sectors_per_dir = (((dpb->DRM+1)<<5)+(dpb->BPS-1))/dpb->BPS;
1230 sectors_per_dir = sectors_per_dir * dpb->BPS;
1231
1232 dpb->CKS = sectors_per_dir/RECORDSIZE;
1233
1234
1235 if (dpb->DSM>=256) {
1236 /* 2 byte pointer and 8 pointer per entry max */
1237 BLKNR_SIZE = 2;
1238 BLKNR_MAX = 8;
1239 }
1240 else
1241 {
1242 /* 1 byte pointer and 16 pointer per entry max */
1243 BLKNR_SIZE = 1;
1244 BLKNR_MAX = 16;
1245 }
1246
1247 /* if the extent mask is a real mask, then we can calculate the number of 1 bits in it.
1248 From this we can calculate the number of extents */
1249 /* the function will only work if EXM is 1,3,7,15.... i.e. if bit 3 is set, bits 2,1 and 0 must be set */
1250 /* it will not handle isolated bits! e.g. EXM=8*/
1251 /* get number of extents from exm bit mask */
1252 dpb->num_extents = 1<<get_bit_count_from_mask(dpb->EXM);
1253
1254
1255 /* I hope this should correctly get the number of blocks per directory entry */
1256 /* a directory entry can only describe a maximum of 16384 bytes */
1257 {
1258 unsigned long max_size;
1259
1260 /* calculate the max size based on the max number of blocks that
1261 can be stored in the directory entry. The max number of blocks
1262 is dependant on DSM. If DMS<=255, then 16 blocks can be stored,
1263 else 8 blocks can be stored */
1264 max_size = BLKNR_MAX * dpb->BLS;
1265
1266 /* divide max size by EXM+1. If this is greater than 16384,
1267 calculate the number of blocks we can store */
1268 if ((max_size/dpb->num_extents)>EXTENTSIZE)
1269 {
1270 BLKNR = (EXTENTSIZE*dpb->num_extents)/dpb->BLS;
1271 }
1272 else
1273 {
1274 /* set to max allowed */
1275 BLKNR = BLKNR_MAX;
1276 }
1277 }
1278 }
1279
sector_exists(uchar * track,ushort SEC1)1280 int sector_exists(uchar *track, ushort SEC1)
1281 {
1282 struct t_header *track_header = (struct t_header *)track;
1283 int i;
1284 struct s_info *sector_info = &track_header->sector[0];
1285 int spt;
1286
1287 spt = track_header->SPT;
1288
1289 /* check if SEC1 exists in sectors available on track 0 */
1290 for (i=0; i<spt; i++)
1291 {
1292 //printf("%x == %x\n", sector_info->sector, SEC1);
1293 if (sector_info->sector == SEC1)
1294 {
1295 return 1;
1296 }
1297
1298 sector_info++;
1299 }
1300
1301 return 0;
1302 }
1303
1304 /* KT - added select format from those available */
select_format(uchar * track)1305 int select_format(uchar *track)
1306 {
1307 struct t_header *track_header = (struct t_header *)track;
1308 int spt;
1309 DPB_list_entry *cur_entry;
1310 DPB_list_entry *dpb_entry_found = NULL;
1311 int found_count = 0;
1312 spt = track_header->SPT;
1313
1314 /* go through list of supported formats */
1315 cur_entry = dpb_list.first;
1316
1317 while (cur_entry!=NULL)
1318 {
1319 /* check if first sector exists in list of sectors in track */
1320 if (sector_exists(track, cur_entry->dpb.SEC1_side1))
1321 {
1322 //printf("%d == %d\n", spt, cur_entry->dpb.SECS);
1323
1324 /* correct sectors per track? */
1325 if (spt == cur_entry->dpb.SECS)
1326 {
1327 /* correct number of sides? */
1328 if (disk_header.nbof_heads==cur_entry->dpb.HDS)
1329 {
1330 if (disk_header.nbof_tracks >=40 /*== cur_entry->dpb.TRKS*/)
1331 {
1332 // found a format that appears to match the format on the disc
1333 if (dpb_entry_found==NULL)
1334 {
1335 dpb_entry_found = cur_entry;
1336 }
1337
1338 //fprintf(stdout, "Found format \"%s\" matching disk image format", cur_entry->ident);
1339 found_count++;
1340 }
1341 }
1342
1343 }
1344
1345 }
1346
1347 cur_entry = cur_entry->next;
1348 }
1349
1350 /* no entry found */
1351 if (dpb_entry_found==NULL)
1352 {
1353 /* format not recognised */
1354
1355 /* no format found */
1356 return -1;
1357 }
1358
1359 if (found_count==1)
1360 {
1361 dpb = &dpb_entry_found->dpb;
1362 dpb_list_entry = dpb_entry_found;
1363
1364 /* found it - update it */
1365 update_dpb(dpb,track);
1366
1367 return 0;
1368 }
1369
1370 /* too many formats to choose from */
1371 return -2;
1372 }
1373
1374 void
initialise(void)1375 initialise(void)
1376 {
1377 /* KT - initialise some data */
1378
1379 cur_trk = -1;
1380 cur_hd = -1;
1381 cur_blk = -1;
1382 directory_dirty = 0;
1383 image_type = 0;
1384 *disk_header.tag = 0;
1385 track = NULL;
1386 blk_alloc = NULL;
1387 directory = NULL;
1388 block_buffer = NULL;
1389 imagefile = -1;
1390 gz_imagefile = 0;
1391 gz_format = 0;
1392 }
1393
1394 /********
1395 Blocks
1396 ********/
1397
get_free_block()1398 int get_free_block() {
1399 /* ^^^^^^^^^^^^^^ */
1400 static int next = 0;
1401 int i;
1402
1403 if (next > dpb->DSM) next = 0;
1404 /* try to allocate next block, if there was a previos one (next!=0) */
1405 if ((next != 0) && (is_free_block(next))) return next++;
1406 /* try to find the first free block */
1407 for (i=dpb->DBL;i<=dpb->DSM;i++) {
1408 if (is_free_block(i)) return i;
1409 }
1410 return -1;
1411 }
1412
1413
1414 /*****************
1415 FS Maintenance
1416 *****************/
1417
1418 int
open_image(char * name,int auto_detect)1419 open_image(char *name, int auto_detect)
1420 {
1421 /* ^^^^^^^^^^
1422 alloc track buffer, blk_alloc, buffer, read directory */
1423
1424 int n;
1425 int result;
1426
1427 /* open file */
1428 if (my_open(name) < 0) {
1429 return -1;
1430 }
1431 n = my_read((uchar*)&disk_header,0x100);
1432 if (n!=0x100) {
1433 return -1;
1434 }
1435 if (!tag_ok()) {
1436 //fprintf(stdout,"\"%s\" is not a DSK image!",name);
1437 return -1;
1438 }
1439 if ((disk_header.nbof_heads<1) || (disk_header.nbof_tracks<1)) {
1440 //fprintf(stdout,"--==>>> open_image: \"%s\"",name);
1441 abandonimage();
1442 return -1;
1443 }
1444
1445 /* added function to malloc block which is size of the biggest track */
1446 malloc_track();
1447
1448 /* check malloc succeded */
1449 if (track==NULL)
1450 {
1451 abandonimage();
1452 return -1;
1453 }
1454
1455
1456
1457 if (!validate_image())
1458 {
1459 //fprintf(stdout, "Image file is corrupted!");
1460 abandonimage();
1461 return -1;
1462 }
1463
1464
1465
1466 /* set up varaibles */
1467 filler = 0xE5;
1468
1469 /* determine disk format */
1470 if (read_track(0,0))
1471 {
1472 abandonimage();
1473 return -1;
1474 }
1475
1476
1477
1478 /* auto-detect image format */
1479 if (auto_detect)
1480 {
1481
1482 result = select_format(track);
1483
1484 if (result==-2)
1485 {
1486 //fprintf(stdout, "Multiple formats found!");
1487 abandonimage();
1488 return -1;
1489 }
1490
1491 if (result==-1)
1492 {
1493 printf("dsk format not recognised heads(%d)\n", disk_header.nbof_heads);
1494 abandonimage();
1495 return -1;
1496 }
1497
1498 //fprintf(stdout, "DSK_FORMAT: %x\n", dpb->SEC1_side1);
1499 cpc_dsk_type = dpb->SEC1_side1;
1500
1501 }
1502 else
1503 {
1504 /* found it - update it */
1505 update_dpb(dpb,track);
1506 }
1507
1508 if (dpb==NULL)
1509 {
1510 //fprintf(stdout, disc_format_not_recognised_string);
1511 abandonimage();
1512 return -1;
1513 }
1514
1515
1516
1517 /* calculate number of blocks and allocate memory */
1518 blk_alloc = (uchar *)malloc(((dpb->DSM+1)+7)>>3);
1519
1520 /* KT - added memory allocate check */
1521 if (blk_alloc==NULL)
1522 {
1523 abandonimage();
1524
1525 return -1;
1526 }
1527
1528 directory = (DirEntry*)malloc(sizeof(DirEntry)*(dpb->DRM+1));
1529
1530 /* KT - added memory allocate check */
1531 if (directory==NULL)
1532 {
1533 abandonimage();
1534 return -1;
1535 }
1536
1537 /* allocate block buffer */
1538 block_buffer = (uchar*)malloc(dpb->BLS);
1539
1540 if (block_buffer==NULL)
1541 {
1542 abandonimage();
1543 return -1;
1544 }
1545
1546 /* get directory information */
1547 get_directory();
1548
1549 return 0;
1550 }
1551
1552 DPB_type system_dpb=
1553 {
1554 0x041, /* SEC1 side 1 */
1555 0x041, /* SEC1 side 2 */
1556 9, /* SECS */
1557 40, /* TRKS */
1558 1, /* HDS */
1559 512, /* BPS */
1560
1561 36, /* SPT */
1562 3, /* BSH */
1563 7, /* BLM */
1564 0, /* EXM */
1565 170, /* DSM */
1566 63, /* DRM */
1567 0xC0, /* AL0 */
1568 0x00, /* AL1 */
1569 16, /* CKS */
1570 2, /* OFS */
1571 0,0,0,
1572 ORDER_SIDES,0,0,5,0,NULL
1573 };
1574
1575 DPB_type system_dpb_big=
1576 {
1577 0x041, /* SEC1 side 1 */
1578 0x041, /* SEC1 side 2 */
1579 10, /* SECS */
1580 40, /* TRKS */
1581 1, /* HDS */
1582 512, /* BPS */
1583
1584 36, /* SPT */
1585 3, /* BSH */
1586 7, /* BLM */
1587 0, /* EXM */
1588 170, /* DSM */
1589 63, /* DRM */
1590 0xC0, /* AL0 */
1591 0x00, /* AL1 */
1592 16, /* CKS */
1593 2, /* OFS */
1594 0,0,0,
1595 ORDER_SIDES,0,0,5,0,NULL
1596 };
1597
1598
1599 DPB_type data_dpb =
1600 {
1601 0x0c1, /* SEC1 side 1 */
1602 0x0c1, /* SEC1 side 2 */
1603 9, /* SECS */
1604 40, /* TRKS */
1605 1, /* HDS */
1606 512, /* BPS */
1607
1608 36, /* SPT */
1609 3, /* BSH */
1610 7, /* BLM */
1611 0, /* EXM */
1612 179, /* DSM */
1613 63, /* DRM */
1614 0xC0, /* AL0 */
1615 0x00, /* AL1 */
1616 16, /* CKS */
1617 0, /* OFS */
1618 0,0,0,
1619 ORDER_SIDES,0,0,5,0,NULL
1620 };
1621
1622
1623 DPB_type data_dpb_big =
1624 {
1625 0x0c1, /* SEC1 side 1 */
1626 0x0c1, /* SEC1 side 2 */
1627 10, /* SECS */
1628 40, /* TRKS */
1629 1, /* HDS */
1630 512, /* BPS */
1631
1632 36, /* SPT */
1633 3, /* BSH */
1634 7, /* BLM */
1635 0, /* EXM */
1636 179, /* DSM */
1637 63, /* DRM */
1638 0xC0, /* AL0 */
1639 0x00, /* AL1 */
1640 16, /* CKS */
1641 0, /* OFS */
1642 0,0,0,
1643 ORDER_SIDES,0,0,5,0,NULL
1644 };
1645
upper(char * s)1646 char *upper(char *s) {
1647 /* ^^^^^ */
1648 char *p=s;
1649
1650 while (*s)
1651 {
1652 *s = toupper(*s);
1653 s++;
1654 }
1655
1656
1657 return p;
1658 }
dpb_list_add_entry(DPB_list * list,DPB_list_entry * entry)1659 void dpb_list_add_entry(DPB_list *list, DPB_list_entry *entry)
1660 {
1661 DPB_list_entry *cur_entry;
1662
1663 /* if list empty add as first item */
1664 if (list->first==NULL)
1665 {
1666 list->first = entry;
1667 }
1668 else
1669 {
1670 /* add to end of list */
1671 cur_entry = list->first;
1672
1673 while (cur_entry->next!=NULL)
1674 {
1675 cur_entry = cur_entry->next;
1676 }
1677
1678 cur_entry->next = entry;
1679 }
1680 }
dpb_list_add_item(DPB_list * list,char * description,char * ident,DPB_type * dpb)1681 void dpb_list_add_item(DPB_list *list,char *description, char *ident, DPB_type *dpb)
1682 {
1683 DPB_list_entry *entry = (DPB_list_entry *)malloc(sizeof(DPB_list_entry));
1684
1685 if (entry!=NULL)
1686 {
1687 if (description==NULL)
1688 {
1689 entry->description = NULL;
1690 }
1691 else
1692 {
1693 entry->description = (char *)malloc(strlen(description)+1);
1694
1695 if (entry->description!=NULL)
1696 {
1697 strcpy(entry->description, description);
1698 }
1699 }
1700
1701 if (ident==NULL)
1702 {
1703 entry->ident = NULL;
1704 }
1705 else
1706 {
1707 entry->ident = (char *)malloc(strlen(ident)+1);
1708
1709 if (entry->ident!=NULL)
1710 {
1711 strcpy(entry->ident, ident);
1712 upper(entry->ident);
1713 }
1714 }
1715
1716
1717 /* copy dpb */
1718 memcpy(&entry->dpb, dpb, sizeof(DPB_type));
1719
1720 /* if cylinders is 40, but used in a 80 track drive, then the drive
1721 head is automatically double stepped */
1722 /* want to use cylinders from .def because this is good for discs
1723 where only 60 tracks are used */
1724 #if 0
1725 /* The 22disk definition uses CYLINDERS to define, from what I can
1726 see the physical number of tracks on the disc media. So, you can
1727 have a 80 track 5.25" drive reading a 40 track format with
1728 or without double step - calculate a decent TRKS from DSM
1729 which specifies the total number of blocks on the disc. */
1730 {
1731 DPB_type *dpb = &entry->dpb;
1732
1733 dpb->BLS = 1 << (dpb->BSH + 7); /* or 2^BSH*128 */
1734
1735 /* calculate the number of tracks from DSM */
1736 dpb->TRKS = (((dpb->DSM+1)*dpb->BLS)+(dpb->OFS*dpb->SECS*dpb->BPS) + ((dpb->DRM+1)<<5))/(dpb->SECS*dpb->BPS*dpb->HDS);
1737 }
1738 #endif
1739
1740 entry->next = NULL;
1741 }
1742
1743 dpb_list_add_entry(list, entry);
1744 }
1745
1746
1747 static void
cpc_dsk_init()1748 cpc_dsk_init()
1749 {
1750 static int loc_initialized = 0;
1751 if (loc_initialized) return;
1752
1753 dpb_list.first = NULL;
1754
1755 initialise();
1756
1757 /* data */
1758 //dpb_list_add_item(&dpb_list,"Data Format", "data", &data_dpb);
1759 dpb_list_add_item(&dpb_list,"data", "data", &data_dpb);
1760 // fix big data format (ex: Prehistorik II)
1761 dpb_list_add_item(&dpb_list,"data_b", "data_b", &data_dpb_big);
1762
1763 /* system */
1764 //dpb_list_add_item(&dpb_list,"System Format", "system", &system_dpb);
1765 dpb_list_add_item(&dpb_list,"system", "system", &system_dpb);
1766 dpb_list_add_item(&dpb_list,"system_b", "system_b", &system_dpb_big);
1767
1768 loc_initialized = 1;
1769 }
1770
1771 //#define DEBUG
1772 int
cpc_dsk_dir(char * filename)1773 cpc_dsk_dir(char *filename)
1774 {
1775 cpc_dsk_init();
1776
1777 cpc_dsk_num_entry = 0;
1778 int error = open_image(filename, 1);
1779 abandonimage();
1780 #ifdef DEBUG
1781 int index;
1782 for (index = 0; index < cpc_dsk_num_entry; index++) {
1783 fprintf(stdout, "[%d] -> '%s'\n", index, cpc_dsk_dirent[index]);
1784 }
1785 #endif
1786 return error;
1787 }
1788