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