/*----------------------------------------------------------------*/ /* MODULE: AUDIR.C */ /* CONTENTS: main()... */ /* AUTHOR: John T. Bell */ /* HISTORY: Last modified on 9/14/88 */ /* */ /* Copyright 1988, by John T. Bell, All Rights Reserved. */ /*----------------------------------------------------------------*/ #include #include #include "bios.h" typedef unsigned char byte; typedef unsigned short word; /* turn off redefinitions in header files */ #define BYTE_DEF #include "prodir.h" #include "ados33.h" #include "cpmdir.h" /*---------------------------------------------------*/ /* Note: Slot 6, Drive 1, is the C: CP/M drive on my */ /* system. Drive C: is is referenced by the */ /* Number 2 to the CP/M BIOS. */ /* A: == Drive 0 */ /* B: == Drive 1 */ /* C: == Drive 2 */ /* Etc... */ /* Change as appropiate for your system. */ /*---------------------------------------------------*/ #define DRIVE 2 /*----------------------------------------------------------*/ /* This is a table of the first 4 bytes which should */ /* appear at track 0 sector 0 of each disk format */ /* expected. This is used to determine which */ /* operating system the disk was written with. The */ /* fifth byte in each row should identify the OS in */ /* the following manner; */ /* */ /* CP/M is 0x00 */ /* AppleDOS is 0x01 */ /* and ProDOS is 0x02 */ /* */ /* Note: The second CP/M entry is for a disk which has */ /* formatted but the CP/M boot tracks were not written. */ /*----------------------------------------------------------*/ #define MAX_TYPE 4 byte disk_id[ MAX_TYPE ][5] = { { 0x01, 0xea, 0xa6, 0x2b, 0x00}, /* CP/M format */ { 0xe5, 0xe5, 0xe5, 0xe5, 0x00}, /* CP/M Disk w/o system */ { 0x01, 0xa5, 0x27, 0xc9, 0x01}, /* Apple Dos 3.3 Disk */ { 0x01, 0x38, 0xb0, 0x03, 0x02} /* ProDOS 1.1.1 Disk */ }; /*---------------------------------------------------*/ /* The following is the sector conversion table */ /* for converting DOS sectors to CP/M sectors. */ /*---------------------------------------------------*/ int dos2cpm[] = {0,15,9,3, 13,7,1,11, 10,4,14,8, 2,12,6,5}; int pro2cpm[] = {0,6,12,2, 8,14,4,10, 11,1,7,13, 3,9,15,5}; main() { int type; int err; type = disktype(); switch(type){ case 0: /* CP/M disk */ printf("*** CP/M Directory ***\n\n"); cpmdir(); break; case 1: printf("*** Apple DOS 3.3 Directory ***\n\n"); dosdir(); break; case 2: printf("*** ProDOS Directory ***\n\n"); prodir(); break; default: printf("udir: Can't identify disk type\n"); break; } /*--------------------------------------------------------*/ /* The following, skips the Aztec CP/M exit code. */ /*--------------------------------------------------------*/ #asm .z80 jp 0 .8080 #endasm } /*--------------------------------------------------------------------------*/ /* Function: int disktype(); */ /* Purpose: Identify a diskette as being CP/M, AppleDOS, or ProDOS. */ /* Returns: 0 for CP/M, 1 for AppleDOS, 2 for ProDOS, */ /* -1 for unidentified, and -2 for error. */ /* Globals: Uses the disk_id[][] table to compare the first four */ /* bytes of the disk and make an identification. */ /* Notes: Disk idents were determined by trial and error. There may */ /* be others (ie; NON-Bootable AppleDOS) which have not been */ /* included in the table. */ /*--------------------------------------------------------------------------*/ int disktype() { byte buff[128]; /* buffer for first track and sector */ byte *bptr; int i,j; int err; if((err = readsect(DRIVE,0,0,buff)) != 0){ /* disk error */ errno = err; return(-2); } for(i = 0; i < MAX_TYPE; i++){ bptr = buff; for(j = 0; j < 4; j++){ if(disk_id[i][j] != *bptr++) break; } if(j >= 4) return(disk_id[i][4] & 0x00ff); } return(-1); } /*--------------------------------------------------------------------------*/ /* Function: cpmdir() */ /* Purpose: Do a low level (without CP/M BDOS assistance) read of the */ /* CP/M directory. A low level directory read is needed here */ /* to enable future porting to other Apple Operating Systems. */ /* Returns: NONE */ /* Notes: Disk is currently hard coded and should be given as an arg */ /* in the future. */ /* */ /*--------------------------------------------------------------------------*/ cpmdir() { char buff[128]; /* disk sector buffer */ int i,err; int disk; int track,sect; struct cpm_entry *dir; int user,j; track = 3; /* track for apple cp/m directory */ for(sect = 0; sect < 12; sect++){ err = readsect(DRIVE,track,sect,buff); if(!err){ dir = (struct cpm_entry *)buff; for(j = 0; j < 4; j++){ if((dir->user_no != 0xe5) /* skip erased file */ &&(dir->extent == 0)){ /* and extra extents */ user = dir->user_no & 0x1f; printf("C%d:%8.8s.%3.3s\n",user,dir->name,dir->ext); } dir++; } } } } /*--------------------------------------------------------------------------*/ /* Function: prodir() */ /* Purpose: This routine reads the Apple DOS directory from */ /* a Pro Dos disk and prints it to the display. */ /* Returns: 0 if no error, -1 otherwise. */ /* Notes: Requires PRODIR.H to define the structures. */ /* */ /*--------------------------------------------------------------------------*/ prodir() { byte buff[513]; /* disk sector buffer */ byte fname[32]; /* space for filename */ int i,err; int block; struct pro_block *dir; int entry_type; int name_len; dir = (struct pro_block *)buff; block = 2; /*---------------------------------------------------*/ /* read sectors until no further catalog links */ /*---------------------------------------------------*/ do{ err = getproblock(block,buff); if(err){ fprintf(stderr,"error %d reading block %d\n",err,block); return(-1); } /*---------------------------------------------------*/ /* Print the directory entries */ /*---------------------------------------------------*/ for(i = 0; i < 13; i++){ entry_type = (dir->dir[i].typ_len & 0x00f0) / 16; name_len = (dir->dir[i].typ_len & 0x000f); setmem(fname,32,'\0'); /* clear the filename space */ strncpy(fname, dir->dir[i].fname, name_len); fixstr(fname); #ifdef xyzzy printf("INFO:%d entry %d len %d name %15.15s\n", i,entry_type,name_len,fname); #endif switch(entry_type){ case 0x0f: /* Volume entry */ printf("VOLUME NAME: %s\n\n", fname); break; case 0x0e: /* Subdirectory header */ break; case 0x0d: /* Subdirectory */ printf("\nSUB-DIRECTORY: %s\n\n", fname); break; case 0: /* Deleted entry */ break; case 1: case 2: case 3: printf("%s\n", fname); break; default: printf("Unknown entry type %d\n",entry_type); break; } } /*---------------------------------------------------*/ /* Get the next Catalog Block */ /*---------------------------------------------------*/ block = dir->next; }while(block > 2); return(0); } /*--------------------------------------------------------------------------*/ /* Function: getproblk( block, buff) */ /* unsigned int block; - ProDOS block number to read. */ /* byte *buff; - Location to store the data read. */ /* Must be 512 bytes long or greater. */ /* Purpose: Read a ProDOS disk block. */ /* Returns: -1 for error, 0 otherwise. */ /* Globals: Uses the pro2cpm[] sector translation table. */ /* Notes: Calculates CP/M tracks and sectors and does all */ /* ProDOS to CP/M sector translation. Reads 4 CP/M sectors. */ /* */ /*--------------------------------------------------------------------------*/ int getproblock(block,buff) int block; byte *buff; { int cpmsect; int err; int track; int sect; int i,j; /*---------------------------------------------------*/ /* Do ProDOS to CP/M sector translation */ /*---------------------------------------------------*/ track = block/8; sect = (block % 8) * 2; cpmsect = pro2cpm[sect] * 2; /*---------------------------------------------------*/ /* Read 4 CP/M sectors and copy into buff */ /*---------------------------------------------------*/ for(i = 0; i < 2; i++){ for(j = 0; j < 2; j++){ err = readsect(DRIVE,track,cpmsect,buff); if(err < 0) return(err); cpmsect++; buff+=128; } sect++; cpmsect = pro2cpm[sect] * 2; } return(0); } /*--------------------------------------------------------------------------*/ /* Function: dosdir() */ /* Purpose: This routine reads the Apple DOS directory from */ /* a DOS 3.3 disk and prints it to the display. */ /* Returns: -1 if error, 0 otherwise. */ /* Notes: Requires ADOS33.H. */ /* */ /*--------------------------------------------------------------------------*/ dosdir() { char buff[257]; /* disk sector buffer */ char fname[32]; /* space for filename */ int i,err; int disk; int track,sect; struct dir_blk *dblk; /* pointer to directory block */ dblk = (struct dir_blk *)&buff[0]; setmem(fname,32,'\0'); /* clear the filename space */ /*---------------------------------------------------*/ /* get VTOC sector */ /*---------------------------------------------------*/ track = 17; /* VTOC begins at track 17 sector 0 */ sect = 0; err = rd_dos_blk(track,sect,buff); /* read the VTOC sector */ if(err){ fprintf(stderr,"error %d track %d sector %d\n",err,track,sect); return(-1); } /*---------------------------------------------------*/ /* get catalog track, sector links */ /*---------------------------------------------------*/ track = dblk->track_lnk; sect = dblk->sect_lnk; /*---------------------------------------------------*/ /* read sectors until no further catalog links */ /*---------------------------------------------------*/ while(track && sect){ err = rd_dos_blk(track,sect,buff); if(err){ fprintf(stderr,"error %d track %d sector %d\n",err,track,sect); return(-1); } /*---------------------------------------------------*/ /* Print the directory entries */ /*---------------------------------------------------*/ for(i=0;i<7;i++){ if((dblk->dir[i].track != (char)0xff)&& (dblk->dir[i].track != (char)0)){ movmem(&dblk->dir[i].fname,fname,30); fixstr(fname); printf("%s\n",fname); } } /*---------------------------------------------------*/ /* Get the next Catalog track and sector */ /*---------------------------------------------------*/ if(track||sect){ track = dblk->track_lnk; sect = dblk->sect_lnk; } } return(0); } /*--------------------------------------------------------------------------*/ /* Function: rd_dos_blk(track, sect, buff); */ /* int track; - track of block to be read; */ /* int sect; - AppleDOS sector to be read; */ /* byte *buff; - Destination for block data, must be at least */ /* 256 bytes long. */ /* */ /* Purpose: read an AppleDOS disk block. */ /* Returns: readsect() error value if error, 0 if no errors occurs. */ /* Globals: Uses the dos2cpm[] sector translation table. */ /* Notes: Does sector translation and reads 2 CP/M sectors. */ /* (DOS sectors are 256 bytes CP/M sectors are 128 bytes.) */ /* */ /*--------------------------------------------------------------------------*/ int rd_dos_blk(track,sect,buff) int track; int sect; char *buff; { int dsect; int err; int i; /*---------------------------------------------------*/ /* Do DOS 2 CP/M sector translation */ /*---------------------------------------------------*/ dsect = dos2cpm[sect]*2; /*---------------------------------------------------*/ /* Read 2 CP/M sectors and copy into buff */ /*---------------------------------------------------*/ for(i = 0; i < 2; i++){ err = readsect(DRIVE,track,dsect,buff); if(err < 0) return(err); dsect++; buff+=128; } return(0); } /*--------------------------------------------------------------------------*/ /* Function: readsect(drive, track, sect, buff) */ /* int drive; - disk drive indentifier. A:=0, B:=1, ..., P:=15 */ /* int track; - track of sector to be read. */ /* int sect; - sector number of sector to be read. */ /* byte *buff; - where to put the data read. */ /* */ /* Purpose: To read a sector from a disk using the low level BIOS calls. */ /* Returns: 0 if everything is AOK. */ /* -1 if a select disk error occurs. */ /* -2 if a sector read error occurs. */ /* Setup: NONE */ /* Globals: NONE */ /* Notes: Use BIOS.H to compile. */ /* */ /*--------------------------------------------------------------------------*/ int readsect(drive,track,sect,buff) int drive; int track; int sect; byte *buff; { int skew; /* internal CP/M skew table */ int tru_sect; /* translated physical sector value */ int err; /*---------------------------------------------------*/ /* Get address of disk parameter block. */ /*---------------------------------------------------*/ skew = bioshl(SELDSK,drive,0); if(skew == 0){ return(-1); } /*---------------------------------------------------*/ /* Select the track */ /*---------------------------------------------------*/ bios(SETTRK,track,0); /*---------------------------------------------------*/ /* Select the sector */ /*---------------------------------------------------*/ tru_sect = bioshl(SECTRAN,sect,skew); bios(SETSEC,tru_sect,0); /*---------------------------------------------------*/ /* Assign destination address (DMA Address) */ /*---------------------------------------------------*/ bios(SETDMA,buff,0); /*---------------------------------------------------*/ /* Read the sector */ /*---------------------------------------------------*/ err = bios(READ,0,0); if(err) return(-2); else return(0); } /*---------------------------------------------------*/ /* Fixes Apple strings for display under CP/M */ /*---------------------------------------------------*/ fixstr(s) byte *s; { while(*s) *s++ &= 0x7f; }