Megalextoria
Retro computing and gaming, sci-fi books, tv and movies and other geeky stuff.

Home » Archive » net.micro.atari16 » TOS->CP/M file transfer program
Show: Today's Messages :: Show Polls :: Message Navigator
E-mail to friend 
Switch to threaded view of this topic Create a new topic Submit Reply
TOS->CP/M file transfer program [message #268844] Thu, 27 February 1986 13:05 Go to next message
Anonymous
Karma:
Originally posted by: holloway

<pre>
Article-I.D.: drivax.307
Posted: Thu Feb 27 13:05:39 1986
Date-Received: Sat, 1-Mar-86 17:58:26 EST
Distribution: net
Organization: Digital Research, Monterey, CA
Lines: 452

The following is a little program I wrote to transfer files from a TOS disk
to a CP/M disk. It works all right in test, but when I run it on the ST all
the block numbers are off by one. Kludging the program to increment the
block number doesn't seem to work. Could someone tell me the format used
for the CP/M disks? The "#define"s show the values I've used, and they
seem to work mostly, except that the files all begin one block farther along
then I think they should.

The program follows.

/*********************************************************** ******************
* STXFER.C
*
* Compile with Alcyon C, using the CLIB supplied with the ST Developers
* Kit.
*
* Program to transfer files from a TOS formatted diskette to a CP/M
* formatted disk. CP/M formatted disks are the same as TOS disks, but
* they have no TOS files, or even a volume label, on them.
*
* This program is my own creation, and has absolutely nothing to do with
* Digital Research, Inc., or Atari, and should not be construed as
* being any part nor portion of any product, announced or no, from either
* of these two companies.
*
* This is released to the public domain, and shouldn't be sold or any
* of that. I reserve the copyright, and the right to change it, or
* fix it, etc.
*
* Copyright (c) 1986, Bruce Holloway
************************************************************ ******************/

/* ***** Note: This will only work on disks which have a sector size
<= 1K.
*****
*/

#include "stdio.h"

#define TOSDISK 0 /* Code for TOS disk */
#define CPMDISK 1 /* Code for CP/M disk */
#define CPMUSER 0 /* CP/M User Number */
#define SECSIZE 512 /* Size of a sector */
#define RECSIZE 128 /* Size of a record */
#define TRACKS 80 /* Number of tracks */
#define SECS 9 /* Sectors per track */
#define BLKSIZE 2048 /* Bytes per block */
#define HIDDEN 18 /* Number of "hidden" sectors */
#define DIRSIZE 128 /* Max number of directory entries */
#define FCBSIZE 32 /* Size of an FCB */
#define DSKSIZE ((TRACKS*SECS)/(1024/SECSIZE)) /* Kilobytes on disk */
#define FILSIZE ((32767/BLKSIZE)*BLKSIZE) /* Size of file buffer */
#define BLOCK0 (HIDDEN+(FCBSIZE*DIRSIZE)/SECSIZE) /* 1st data sector */
#define NUMBLKS ((TRACKS*SECS-BLOCK0)/(BLKSIZE/SECSIZE)) /* # blocks on disk */
#define MAPSIZE (NUMBLKS/8+1) /* Size of free block map, in bytes */

char fcbs[SECSIZE/FCBSIZE][FCBSIZE]; /* Buffer for directory entries */
char blkmap[MAPSIZE]; /* Free block map */
char buffer[FILSIZE/BLKSIZE][BLKSIZE]; /* File buffer */
char tosname[40]; /* TOS file name */
char cpmname[40]; /* CP/M name */
int curdisk; /* Current disk in drive, 0 == TOS */
int mapmade; /* Is the map made? */

main(){
intro();
do{
get_names();
xfer();
} while(morefiles());
extro();
pexit();
}

intro(){
curdisk = -1;
mapmade = 0;
cprintf("Atari TOS -> CP/M File Transfer Program\n\n");
}

get_names(){
cprintf("Name of the TOS file to transfer? "); getline(tosname,35);
cprintf("\nName of the CP/M file? "); getline(cpmname,35);
cprintf("\n");
}

xfer(){
int handle, left, blocks, fcbnum, blknum, extent, block;
char fcb[FCBSIZE];
long f_read();

select(TOSDISK);
handle = f_open(tosname,0);
if(handle < 0){
cprintf("%%% File Not Found %%%\n");
return;
}
blknum = FCBSIZE/2; extent = -1;
do{
if(!(left = (int)f_read(handle,(long)FILSIZE,buffer))) continue;
if(left < 0){
cprintf("%%% Error while reading TOS file %%%\n");
return;
}
blocks = left/BLKSIZE + ((left%BLKSIZE) > 0);
for(left=0; left++ < blocks;){
if(blknum == FCBSIZE/2){
if(extent++ != -1){
if(left == blocks) fcb[15] = 0x80;
if((fcbnum = getfcb()) == -1){
cprintf("%%% Out of directory entries %%%\n");
return;
}
putfcb(fcbnum,fcb);
}
makfcb(cpmname,fcb);
fcb[0] = CPMUSER;
fcb[12] = extent;
blknum = 0;
}
if((block = firstfree()) == -1){
cprintf("%%% Out of disk space %%%\n");
return;
}

fcb[16+blknum++] = block+1;

fcb[15] += BLKSIZE/RECSIZE;
writeblock(block,buffer[left-1]);
}
} while(left == FILSIZE);
if((fcbnum = getfcb()) == -1){
cprintf("%%% Out of directory entries %%%\n");
return;
}
putfcb(fcbnum,fcb);
f_close(handle);
cprintf("Transfer complete!\n");
}

/* Select the CP/M or TOS disk. Init internal tables if selecting CP/M disk
for the first time.
*/

select(disk)
int disk;
{
char iline[5];
int i, j, dleft, cursec, indx;

if(disk == curdisk) return;
cprintf("Please insert %s disk and press <RETURN> -- ",
(disk==CPMDISK)?"CP/M":"TOS");
getline(iline,3);
if(((curdisk = disk) == CPMDISK) && !mapmade){
for(i=0; i<MAPSIZE;)
blkmap[i++] = 0;
for(dleft=i=0, cursec=HIDDEN; i<DIRSIZE; ++i){
if(!dleft){
indx=0;
readsector(cursec++,fcbs);
dleft = SECSIZE/FCBSIZE;
}
if(fcbs[indx][0] != 0xE5)
for(j=16; j<32; ++j)
setblock(fcbs[indx][j]);
++indx;
--dleft;
}
mapmade = 1;
}
}

/* Mark a block as used */

setblock(block)
int block;
{
blkmap[block/8] |= (1 << block%8);
}

/* Return the first unused block number, or -1 if the disk is full */

firstfree(){
int byte, bit, block, found;

if(!mapmade) select(CPMDISK);
for(byte=block=found=0, bit=1; block<NUMBLKS; ++block){
if(!(blkmap[byte] & bit)){ found=1; break; }
if((bit <<= 1) == 0x100){ ++byte; bit=1; }
}
return((found) ? block : -1);
}

/* Write a block to the CPM disk */

writeblock(block,buf)
int block;
char buf[][SECSIZE];
{
int secnum, i;

select(CPMDISK);
setblock(block);
secnum = BLOCK0 + (block*(BLKSIZE/SECSIZE));
for(i=0; i<BLKSIZE/SECSIZE; ++i, ++secnum)
writesector(secnum,buf[i]);
}

/* Return the number of the first free FCB, or -1 if all are used */

getfcb(){
int free, left, i;

select(CPMDISK);
for(free=left=0; free<DIRSIZE; ++free, ++i){
if(!left){
readsector(HIDDEN+free/(SECSIZE/FCBSIZE),fcbs);
left = SECSIZE/FCBSIZE;
i = 0;
}
if(fcbs[i][0] == 0xE5) return(free);
--left;
}
return(-1);
}

/* Write out an FCB */

putfcb(entry,fcb)
int entry;
char fcb[];
{
int i, j, sec;

select(CPMDISK);
readsector(sec=HIDDEN+entry/(SECSIZE/FCBSIZE),fcbs);
i = entry%(SECSIZE/FCBSIZE);
for(j=0; j<FCBSIZE; ++j) fcbs[i][j] = fcb[j];
writesector(sec,fcbs);
}

/* Write a sector to the CP/M disk */

writesector(secnum,buf)
int secnum;
char *buf;
{
select(CPMDISK);
rwabs(1,buf,1,secnum,0);
}

/* Read a sector from the CP/M disk */

readsector(secnum,buf)
int secnum;
char *buf;
{
select(CPMDISK);
rwabs(0,buf,1,secnum,0);
}

#define FCB struct _fcb
FCB{
char f_dr, f_name[8], f_ext[3], f_junk[20];
};

makfcb(fspec,fcb)
char *fspec;
FCB *fcb;
{
static int state, index, i, ch;
static char thold[40], *ts;

state = index = 0;
for(i=0, ts = (char *)fcb ; i++ < sizeof(FCB); *ts++ = 0 );
for(i=1, ts = (char *)fcb+1; i++ < 12 ; *ts++ = ' ');

do{
switch(ch = toupper(*fspec++)){
case ':':
if(!state){
state=1;
thold[index] = 0;
for(index=0; i = thold[index++];)
if(isupper(i)) fcb->f_dr = i-'A'+1;
index=0;
}
else goto nch;
break;
case '.':
if(state < 2){
state=2;
thold[index]=0;
for(index=0; (i=thold[index]) && index<8;)
fcb->f_name[index++] = i;
index=0;
}
else goto nch;
break;
case '\0':
thold[index]=0;
if(state < 2)
for(index=0; (i=thold[index]) && index<8;)
fcb->f_name[index++] = i;
else
for(index=0; (i=thold[index]) && index<3;)
fcb->f_ext[index++] = i;
goto fixup;
default:
nch: thold[index++] = ch;
break;
}
} while(1);
fixup:
}

/* Oddly, I *don't* have the Atari Developer's Kit, so these routines make
up the TOS entry points. These can be removed or modified if you don't
need them.
*/

getline(buf,count)
char buf[];
int count;
{
buf[0] = count;
trap1(10,buf);
buf[buf[1]+2] = 0;
strcpy(buf,buf+2);
printf("\n");
}

f_open(pname,mode)
char *pname;
int mode;
{
return(trap1(0x3D,pname,mode));
}

long f_read(handle,count,buf)
int handle;
long count;
char *buf;
{
select(TOSDISK);
return((long)trap1(0x3F,handle,count,buf));
}

f_close(handle)
int handle;
{
trap1(0x3e,handle);
}

pexit(){
trap1(0x4c,0);
}

rwabs(rwflag,buf,count,recno,dev)
int rwflag,count,recno,dev;
char *buf;
{
trap13(4,rwflag,buf,count,recno,dev);
}

morefiles(){
char iline[10];

printf("Transfer any more files? ");
getline(iline,5);
return(iline[0] == 'y' || iline[0] == 'Y');
}

extro(){
printf("All transfers completed.\n");
}

co(ch)
int ch;
{
trap1(2,ch);
}

flush(){}

/*********************************************************** *****************
* These are the assembler routines needed to talk to TOS.
*
* Break these off into a file called "XMSTASM.S" or somesuch and
* assemble and link them seperately.
************************************************************ *****************/

#if 0
.Globl _trap1,_trap13,_trap14

************************************************************ *************
* TRAP1(fn,p1,p2,...,pn) *
* *
* Call GEMDOS with the specified parameter block. *
************************************************************ *************

_trap1:
Move.L (SP)+,tr1ra
Trap #1
Move.L tr1ra,-(SP)
Rts

************************************************************ *************
* TRAP14(fn,p1,p2,...,pn) *
* *
* Call Atari BIOS Extension with the specified parameters. *
************************************************************ *************

_trap14:
Move.L (SP)+,tr14ra
Trap #14
Move.L tr14ra,-(SP)
Rts

************************************************************ *************
* TRAP13(fn,p1,p2,...,pn) *
* *
* Call GEMDOS BIOS with the specified parameters. *
************************************************************ *************

_trap13:
Move.L (SP)+,tr13ra
Trap #13
Move.L tr13ra,-(SP)
Rts

.Bss

tr14ra: Ds.L 1 Return address from TRAP 14
tr13ra: Ds.L 1 Return address from TRAP 13
tr1ra: Ds.L 1 Return address from TRAP 1

.End

#endif
--

+----------------------------------------------------------- -----------------+
|Whatever I write are not the opinions or policies of Digital Research, Inc.,|
|and probably won't be in the foreseeable future. |
+----------------------------------------------------------- -----------------+

Bruce Holloway

....!ucbvax!hplabs!amdahl!drivax!holloway
(I'm not THAT Bruce Holloway, I'm the other one.)
</pre>
Re: TOS->CP/M file transfer program [message #282942 is a reply to message #268844] Mon, 03 March 1986 20:06 Go to previous message
Bicer.ES is currently offline  Bicer.ES
Messages: 31
Registered: May 2013
Karma: 0
Member
<pre>
Article-I.D.: Xerox.860303-170727-1678
Posted: Mon Mar 3 20:06:36 1986
Date-Received: Sat, 8-Mar-86 04:54:01 EST
References: <307@drivax.UUCP>
Sender: daemon@ucbvax.BERKELEY.EDU
Organization: The ARPA Internet
Lines: 12

I have just received CPM.TOS. When I execute it it asks for a CPM disk,
and none of the disks I seem to be good enough. What do I have to do to get
it to work with my CPM programs? Also, is the speed comparable to a,
lets say a 4Meg Z80?

Thaks in advance,
Jack Bicer


Bicer.ES@Xerox.COM
-or-
Bicer.ES@Xerox.ARPA
</pre>
  Switch to threaded view of this topic Create a new topic Submit Reply
Previous Topic: --- EA boycott ---
Next Topic: rtxdemo as promised
Goto Forum:
  

-=] Back to Top [=-
[ Syndicate this forum (XML) ] [ RSS ] [ PDF ]

Current Time: Fri Apr 19 19:52:32 EDT 2024

Total time taken to generate the page: 0.10471 seconds