/************************************************* PCSWP Eugene Nolan 2/10/89 c/o DHN* RCPM 215-623-4040 This utility allows you access to IBM PC 320/360k floppies if: 1 - Your systems has a means of accessing DS/DD 5.25 with 512 byte sectors and 8 or 9 physical sectors/track. This means that your system must support 4k or 4.5k bytes per track on your floppy. It must also alternate heads when it overflows the current track. It: 1 - Allows you to spec the drive the DOS disk is on 2 - Get a directory listing of the DOS disk 3 - Copy a single file at a time to the DOS disk (no wildcards) from a specified CPM drive/user 4 - Sweep the DOS disk A - Foreward or backwards B - View a file ( if file is not ASCII, sorry ) C - Delete a DOS file D - Tag a DOS file for later mass copy E - Untag a previously tagged file F - Copy all tagged files to a designated CPM drive/user 5 - During file copies from/to the DOS disk, you will be asked whether to proceed on not if the destination file exists Limitations: 1 - Only 320k and 360k format supported. 2 - File names with 05 in dos directory as first character of name may display funny, as no conversion to the true E5h will be made. 3 - For file copys from/to the DOS disk, no data verification is done 4 - No autologin of DOS disk, if you change the disk, tell the program by re-specifying the drive the DOS disk is on 5 - Checks are made to verify the DOS disk is a DOS disk of the supported formats, but given the right circumstances, it is possible to trick the program (possible but unlikely). Many commercial systems have a utility that will allow you to define this format. For those of you who wish to roll your own DPB, the values are: DPBF: ;DISK PARAMETER BLOCK for IBM 360k DW 36 ;SECTORS PER TRACK ( 32 if 320k disk) DB 3 ;BLOCK SHIFT FACTOR DB 7 ;BLOCK MASK DB 0 ;EXTENT MASK DW 359 ;DISK SIZE-1 (319 if 320k disk) DW 63 ;DIRECTORY MAX (Not applicable) DB 128+64 ;ALLOC 0 ditto DB 0 ;ALLOC 1 ditto DW 8 ;CKS ditto DW 0 ;TRACK OFFSET ditto General Notes: This program is written in Small C 2.11. In doing so it makes use of some of Small C's internal data bases (namely _fcbptr) and it's method of allocating storage for global variables. In doing so, it will probably not compile correctly with ANY commercial compiler. Also note again, if you change the 'DOS' disk, TELL THE PROGRAM by using the SELECT DOS DISK function from the main menu. And please do not get in the habit of Control-C'ing out of it, Small C lets you do it, but there may be side effects, use the exit from the main menu. ( Only applies if you have been able to succesfully select a DOS disk). The program in it's current version is somewhat slow in it's write's to the DOS floppy. This is because, for the time being, the BIOS calls to 'write sector' are initiated with a 'write to directory' code, which flushes each 128 byte CPM sector individually, regardless of any allocation management code in the BIOS. ***************************************************************/ #define VER 0 /* current version of this code */ #define REV 5 /* current revision level */ /* Psuedo 'c' structure for dos directory entry, DO NOT change order */ char dfilen[11], /* dos file name from directory */ dattri, /* dos attribute */ dresrv[10], /* dos reserved */ dhms[2], /* dos hour/min/sec */ dmdy[2]; /* dos month/day/year */ int ddclus, /* dos root cluster */ dfllsb, /* dos file length LSB */ dflmsb; /* dos file length MSB */ char cfilen[15], /* cpm file name for build fcb */ cldat[1024], /* cluster data stored here */ taghld[224], /* Holds tags of files on DOS write functions */ cpmdsk, /* CPM drive to copy to */ *dirent; /* pointer to current dir entry in dir[] on DOS disk */ int cclust, /* current cluster being processed */ newclu, /* next cluster to allocate on write */ clupnt, /* address for newclu */ user, /* CPM user to copy to */ empdsk, /* ==112 if no usable files on dos disk */ swppnt; /* pointer into dir[] for sweep function */ #define SETUSR 32 /* CPM BDOS call for set user # */ #define SETDRV 14 /* ditto for set default drive */ #define GETDRV 25 /* ditto for get default drive */ char *pfat0, /* pointer to DOS fat0 */ *pfat1, /* pointer to dos fat1 */ fat0[1024], /* hold MS-DOS FAT 0 (if 360k) */ fat[1024], /* Holds MS-DOS FAT 1 (if 320k,else fat0&1 if 320) */ dir[3584]; /* Holds MS-DOS Directory */ char filenam[16]; /* Filename we are copying to CPM */ int seldsk, /* Disk MS-DOS is on, A=0,B=1 */ biodpb, /* ==0 if BIOS said bad disk selected */ track, /* CPM track on MS-DOS disk */ sector, /* CPM sector on MS-DOS disk */ fsize, /* DOS file size in K */ swpsiz, /* size of all files tagged in K */ dirsiz, /* total k of all files on disk */ fillsb, /* current count of bytes to write LSB */ filmsb, /* current count of files to write MSB */ dsmax, /* max sector to read based upon 320/360k */ fatsiz; /* size of fat based upon 320/360k */ int disp; /* ==1 if display directory */ char *fatpnt, /* pointer to fat[] */ *dirpnt, /* pointer to dir[] */ *dma, /* pointer to set dma address to */ *jnkpnt; /* used in file size calc and FAT verification */ int maxsec, /* =32 for 320k, =36 for 360k */ maxclu, /* =315 for 320k, = 355 for 360k */ cpmspt, /* Seldsk returns the DPB's CPMSPT here */ sptcpm; /* used for verifying DOS format matches CPM */ extern _fcbptr[10]; /* Small C pointers to FCB's it builds */ #define STDIN 0 /* Small C's channel number for console input */ /************** Start here ***************/ main() { int i,flag; char d; #asm lhld 1 ; get address of warm boot in BIOS mvi l,1bh shld dtosel+1 ; store address of BIOS SELDSK jump mvi l,1eh shld ttosel+1 ; store address of BIOS SETTRK mvi l,21h shld stosel+1 ; store address of BIOS SETSEC mvi l,24h shld dmasel+1 ; store address of BIOS SETDMA mvi l,27h shld readsc+1 ; store address of BIOS READSC mvi l,2ah shld writsc+1 ; store address of BIOS WRITSC #endasm seldsk=255; /* flag no disk selected yet */ printf("\n\n **** PCSWP %d.%d ****\n\n",VER,REV); printf(" Gene Nolan\n\n"); flag=1; while(flag) { i=menu(); /* display menu and get selection */ switch (i) { case 1: /* select disk for DOS files */ printf("\nEnter drive DOS disk is on (A,B,,,) : "); d=getchar(); d=toupper(d); if ((d>='A')&&(d<='P')) { seldsk=d-65; rdwrdr(0); /* convert to 0-15 and read FAT's and directory */ if(!biodpb) { seldsk=255; printf("\n\n ** BIOS rejected drive"); force(); } if(!((sptcpm==32)||(sptcpm==36))) { /* BIOS DPB CPMSPT */ seldsk=255; printf("\n\n *** Disk DPB definition not correct,"); printf(" Need SPT=32 or 36, ABORTED ***\n"); force(); } if(seldsk!=255) { if(sptcpm!=maxsec) { /* check disk DPB is correct */ seldsk=255; printf("\n\n ** DPB CPMSPT(%d) != DOS SPT(%d), aborted\n", sptcpm,maxsec); force(); } else { printf(" *** 3"); if(maxsec==32) putchar('2'); else putchar('6'); printf("0 K disk found ***\n"); } } } else { printf("\n\n ** A->P only!"); force(); } break; case 2: disdir(); break; /* DOS disk directory */ case 3: dosswp(); break; /* sweep function */ case 4: cpmdos(); break; /* Copy CPM file to DOS disk */ case 5: flag=0; break; /* done */ default: } } } /* ********** */ menu() /* display menu */ { printf("\n\n"); printf(" 1 = Select drive with DOS files on (A,B,C,,,)\n"); printf(" 2 = DOS disk directory\n"); printf(" 3 = Sweep DOS disk\n"); printf(" 4 = Copy to DOS\n"); printf(" 5 = Quit\n"); printf("\nChoice = "); return((getchar()-48)&255); } /* ************* */ rdwrdr(rdwr) int rdwr; /* read/write FAT's/DIR from dos disk */ { int i,defdrv,tdsk; defdrv=_bdos(GETDRV,0); /* get CPM BDOS default drive */ seldk(); /* select disk given by seldsk */ sptcpm=cpmspt; /* save what seldsk returned from DPB */ if(!biodpb) return(1); /* BIOS returned a 0, bad drive selected */ if(rdwr) { printf("\n\n Writing"); suwrdr(); /* set up for FAT/DIR write */ } else { printf("\n\n Reading"); if(surdwr()) return; /* set up for FAT/DIR read */ } printf(" DOS FAT's and directory\n"); dma=pfat0; /* start dma to/from memory here */ for(i=4;i %dk ",swpsiz); /* if any tagged, show size */ } } /* ***************** */ mascop() { /* copy all tagged files */ int i; i=0; if(empdsk==113) { printf(" no files! \n"); return; } printf(" Dest Drv(A,B,,) = "); /* ask for destination drive */ cpmdsk=getchar(); cpmdsk=toupper(cpmdsk); i=cpmdsk&255; if((i<65)||(i>81)) { printf("\n\n ** drive A-P only"); force(); return; } if(askusr()) return; /* get destination user */ for(i=0;i<112;i++) { /* check tags for all files in directory */ dma=dir+i*32; if (*(dma+12)==1) { /* ==1= tagged */ *(dma+12)=0; /* untag it */ cfdos(); /* copy this file to CPM */ } } } /* ***************** */ cfdos() { /* copy from dos to cpm */ int *cfd; char b; movdir(); /* build psuedo structure */ cfilen[0]=cpmdsk; /* put in destination disk */ cfilen[1]=':'; strncpy(&cfilen[2],dfilen,8); cfilen[10]='.'; /* move filename over */ strncpy(&cfilen[11],&dfilen[8],3); printf(" Copying to %c%d:%s",cfilen[0],user,&cfilen[2]); fillsb=dfllsb; filmsb=dflmsb; /* copy filesize to working */ cfd=fopen(cfilen,"r"); if(cfd) { fclose(cfd); printf(" exists, delete(Y/N) "); b=getchar(); b=toupper(b); if((b&255)!='Y') { printf(" aborted\n"); return; } } cfd=fopen(cfilen,"w"); /* open file for writing */ if(!cfd) { printf("\n\n ** could not open, no copy"); force(); return; } cclust=ddclus; /* get root cluster */ while(cclust!=-1) { /* while not last cluster */ rdwrcl(0); /* read cluster */ #asm lxi h,fillsb ; filmsb::lsb=filmsb:lsb-400h mvi c,0 mov a,m ora a sbb c mov m,a inx h mov a,m sbi 4 mov m,a inx h mov a,m sbb c mov m,a inx h mov a,m sbb c mov m,a #endasm if(filmsb<0) { /* less than 1024 left */ fillsb+=1024; jnkpnt=cldat+fillsb; *(jnkpnt+1)=26; /* put in EOF(1Ah) */ fwrite(cldat,1,fillsb,cfd); /* write to CPM */ } else fwrite(cldat,1,1024,cfd); /* read cluster,write to cpm */ nextcl(); /* get next cluster number */ } if(ferror(cfd)) { printf("\n\n ** Error writing file "); force(); } fclose(cfd); putchar('\n'); } /* ******* */ viewfl() { /* view DOS file */ int i,j,vsize,lcnt; movdir(); /* build psuedo structure */ lcnt=1; fillsb=dfllsb; filmsb=dflmsb; /* copy filesize to working */ cclust=ddclus; /* get root cluster */ printf("\n\n *** Ctrl-C aborts\n"); while(cclust!=-1) { /* while not last cluster */ rdwrcl(0); /* read cluster */ #asm lxi h,fillsb ; filmsb:lsb=filmsb:lsb-400h mvi c,0 mov a,m ora a sbb c mov m,a inx h mov a,m sbi 4 mov m,a inx h mov a,m sbb c mov m,a inx h mov a,m sbb c mov m,a #endasm if(filmsb<0) vsize=fillsb+1024; /* less than 1024 */ else vsize=1024; jnkpnt=cldat; for(i=0;i4087) cclust=-1; /* if last cluster, set=-1 */ } /* ************** */ rdwrcl(rdwr) int rdwr; { /* rd/wr whole cluster given by cclust to cldat[] */ int i,cpmsec,defdrv,d; defdrv=_bdos(GETDRV,0); cpmsec=(((cclust-2)*2)+(dsmax/4))*4; /* calc absolute 128 byte sector */ dma=cldat; /* put data here */ seldk(); /* select dos disk */ for(i=0;i<8;i++) { /* read 8 128 byte sectors=1 cluster */ /* printf(" dma=%x, cpmsec=%d\n",dma,cpmsec); */ track=cpmsec/maxsec; sector=cpmsec%maxsec; setdma(); settrk(); setsec(); if(rdwr) wsectr(); else rsectr(); cpmsec+=1; dma+=128; } d=seldsk; /* restore BDOS defualt disk */ seldsk=defdrv; seldk(); seldsk=d; } /* ********** */ fsizek() { /* calc file size in K */ #asm lhld jnkpnt ;get address of 2 word file size inx h mov e,m ; point to second byte inx h mov d,m inx h mov l,m ; l/d/e has high 3 bytes of file size mvi c,2 fsizshf: ora a ; shift l/d/e 2 bits right mov a,l rar mov l,a mov a,d rar mov d,a mov a,e rar mov e,a dcr c jnz fsizshf xchg ; hl now has byte count/400h inx h shld fsize #endasm } /* *********** */ cpmdos() { /* copy CPM file to DOS disk */ int *cfd,i; char b; if(seldsk==255) { nodos(); return; } if((fredir()==112)||(gnewcl()>maxclu)) { printf("\n\n ** No Room on DOS"); force(); return; } putchar('\n'); if(askusr()) return; /* if bad dest user, abort */ printf("File name NAME.EXT = "); /* ask for file to copy */ _gets(cfilen,15,STDIN,0); /* read response, 0 terminated */ cfd=fopen(cfilen,"r"); /* try to open */ if(!cfd) { printf("\n\n ** Not found"); force(); return; } dma=_fcbptr[3]+1; /* point to SMC's FCB */ for(i=0;i<11;i++) *dma=(*dma++)&127; /* strip high bit */ for(i=0;i<112;i++) { dma=dir+i*32; /* see if file exists on DOS disk */ if(!(*(dma+13)==255)) { /* look at our 'file number' field to see if we found valid name here */ if(!(strncmp(dma,_fcbptr[3]+1,11))) { i=112; printf(" exists, overwrite(Y/N) "); b=getchar(); b=toupper(b); if((b&255)=='Y') { deldos(); fredir(); gnewcl(); } else { fclose(cfd); printf(" aborted\n"); return; } } } } strncpy(dfilen,_fcbptr[3]+1,11); /* copy from Small C's internal FCB to psuedo structure file name */ dfllsb=dflmsb=0; /* filesize=0 */ ddclus=cclust=newclu; /* base cluster=current cluster= unused cluster */ while(newclu!=4095) { /* ==4095= CPM EOF found */ fsize=fread(cldat,1,1024,cfd); /* read from CPM */ sumsiz(); rdwrcl(1); /* sum amount read */ if(fsize==1024) { /* if 1k read */ if(gnewcl()>maxclu) { /* get a new cluster */ printf(" \n\n *** DOS DISK FULL, Copied file BAD **\n\n"); force(); newclu=4095; } else { tagclu(); cclust=newclu; } /* current cluster=new one */ } else { newclu=4095; /* CPM EOF, tag last cluster with FFF */ tagclu(); } } i=ferror(cfd); fclose(cfd); if(i) { printf("\n\n ** Error reading file, Copied file BAD, disk select aborted"); force(); seldsk=255; } else { /* good file copy */ dattri=32; /* Mark archive (not changed) */ #asm lhld dirpnt ; copy psuedo structure to dir[] area */ lxi d,dfilen mvi c,20h ; 32 bytes ctodir: ldax d mov m,a inx h inx d dcr c jnz ctodir lhld dirpnt ; Take away CPM's attribute bits mvi c,0bh nfattr: mov a,m ani 7fh mov m,a inx h dcr c jnz nfattr #endasm rdwrdr(1); /* write FATS & DIR */ } } /* ****** */ askusr() { printf(" User = "); scanf("%d",&user); if((user<0)||(user>15)) { printf("\n\n ** User 0-15 only"); force() ; return(1); } _bdos(SETUSR,user); return(0); } /* ********* */ sumsiz() { /* sum up file size in double precision */ int j; #asm lhld fsize ; current amount read (0-1024) xchg lhld dfllsb ; sum with previous total dad d shld dfllsb lda dflmsb aci 0 sta dflmsb #endasm } /* *********** */ writcl() { printf("writ cclust= %d",cclust); } /* ******** */ tagclu() { /* point cclust at newclu */ jnkpnt=(cclust*24)/16; /* offset from fat[0] =cluster # * 1.5 */ #asm ; lxi d,fat lhld pfat1 xchg lhld jnkpnt dad d lda cclust ani 1 jnz clhigh lda newclu mov m,a inx h mov a,m ani 0f0h mov c,a lda newclu+1 ora c mov m,a jmp dsclu clhigh: xchg lhld newclu xchg mvi c,4 shclu: ora a mov a,e ral mov e,a mov a,d ral mov d,a dcr c jnz shclu mov a,m ani 0fh ora e mov m,a inx h mov m,d dsclu: #endasm } /* ****** */ fredir() { /* find a free directory entry */ int i; char b; dirpnt=dir; /* start looking at first entry */ i=0; b=1; while((b&255)&&(i<112)) { /* while this entry used */ b=*dirpnt; /* get status */ switch (b&255) { case 0: /* not used */ case 229: b=0; break; /* erased */ default : dirpnt=dirpnt+32; b=*dirpnt; i+=1; /* look at next entry */ } } return(i); } /* ****** */ gnewcl() { /* get an unallocated cluster */ newclu=2; jnkpnt=1; /* start looking at cluster 2 */ while((jnkpnt==1)&&(newclu<=maxclu)) { clupnt=(newclu*24)/16; /* offset from fat[0]=cluster*1.5 */ #asm ; lxi d,fat lhld pfat1 xchg lhld clupnt lda newclu dad d ani 1 jnz newhgh mov a,m ora a jnz notfre inx h mov a,m ora a jnz notfre dcx h mvi m,0ffh inx h mov a,m ani 0f0h ori 0fh mov m,a jmp isfre newhgh: mov a,m ani 0f0h jnz notfre inx h mov a,m ora a jnz notfre dcx h mov a,m ani 0fh ori 0f0h mov m,a inx h mvi m,0ffh isfre: lxi h,0 shld jnkpnt notfre: #endasm if(jnkpnt) newclu+=1; /* last one used, check next one */ } return(newclu); } /* ******** */ force() { /* error occured, make operator hit a key */ int i; printf(" *** hit any key *** \n"); i=getchar(); } /* ******* */ nodos() { /* say no DOS disk selected */ printf("\n\n ** NO DOS DISK SELECTED"); force(); }