Atari/SRC/unix2atr-0.9.c

926 lines
30 KiB
C

/************************************************************************/
/* unix2atr.c */
/* */
/* Preston Crow */
/* Public Domain */
/* */
/* Extract files from a Unix directory tree and create a MyDOS */
/* ATR-format disk image file. */
/* */
/* To-do for version 1.0: */
/* Eliminate any bugs */
/* Fix up the DOS 2.5 boot sectors. */
/* * Adjust for DOS.SYS if it is there for DOS2.0/2.5. */
/* */
/* To-do after 1.0: */
/* Support for DOS2.0D?? (256-byte sectors without MyDOS) */
/* * Is it any different from 2.0S? */
/* Support for SpartaDOS */
/* * This will probably have to be coded by someone else, */
/* as I'm not terribly interested in it. */
/* Support for more MyDOS versions */
/* * Simply a matter of detecting the version and writing */
/* out the right boot sectors. */
/* */
/* Version History */
/* */
/* 14 Mar 98 Version 0.9 Preston Crow <crow@cs.dartmouth.edu> */
/* */
/* Auto detect MyDOS version and use correct boot sectors. */
/* This needs to be updated for additional versions; */
/* currently only 4.50 and 4.53 are supported. */
/* */
/* Fixed segfault with directories with > 64 files. */
/* */
/* Fixed a bug in the writing of file data--it's right now */
/* */
/* Cleaned up the MyDOS boot sector data. It may still */
/* be sensitive to different versions of MyDOS. */
/* */
/* 24 Feb 98 Version 0.8 Preston Crow <crow@cs.dartmouth.edu> */
/* Add '-s' option to skip the first 720 sectors. */
/* This is useful to protect against corruption from */
/* files that do raw sector I/O, and to save room to write */
/* the DOS files. */
/* Even with this flag, DOS.SYS will be written at sector 4 */
/* */
/* VTOC is now generated for DOS2.5 enhanced density images. */
/* */
/* Boot sectors are correct for MyDOS and DOS2.0/2.5, */
/* except that they aren't adjusted to reflect the disk */
/* parameters or the existence of DOS.SYS. */
/* */
/* DOS.SYS, DUP.SYS, and AUTORUN.SYS will be the first */
/* files written if they are found. */
/* */
/* Directory sorting is case-insensitive if '-u' is */
/* specified, so the resulting image has a sorted directory. */
/* */
/* 21 Feb 98 Version 0.7 Preston Crow <crow@cs.dartmouth.edu> */
/* Bug fix: ATR "sector" count is now correct. */
/* (Why did they use such a strange formula?) */
/* Initial writing of boot sector and VTOC. */
/* */
/* Still no support for extended DOS 2.5 VTOC. */
/* */
/* Should include file numbers for non-MyDOS disks. */
/* */
/* 7 Feb 98 Version 0.6 Preston Crow <crow@cs.dartmouth.edu> */
/* Bug fixes */
/* */
/* 7 Jun 95 Version 0.5 Preston Crow <crow@cs.dartmouth.edu> */
/* Mostly works except: */
/* MyDos format is the only one that works. */
/* bitmaps aren't written to the image */
/* boot sectors aren't created */
/* */
/************************************************************************/
/************************************************************************/
/* Include files */
/************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/dir.h>
#include <string.h>
#include <unistd.h>
/************************************************************************/
/* Macros and Constants */
/************************************************************************/
#define ATRHEAD 16
#define USAGE "unix2atr [-dumps] #sectors atarifile.atr [directory]\n Flags:\n\t-d Double density sectors\n\t-u Convert filenames to upper case\n\t-m MyDOS format disk image\n\t-s skip the first 720 sectors\n\t-p print debugging stuff\n"
/* SEEK: seek offset in the disk image file for a given sector number */
#define SEEK(n) (ATRHEAD + ((n<4)?((n-1)*128):(3*128+(n-4)*secsize)))
/************************************************************************/
/* Data types */
/************************************************************************/
struct atari_dirent {
unsigned char flag; /* set bits:
7->deleted
6->normal file
5->locked
4->MyDOS subdirectory
3->???
2->??? \ one for >720, one for >1024 ?
1->??? / all for MyDOS?
0->write open */
unsigned char countlo; /* Number of sectors in file */
unsigned char counthi;
unsigned char startlo; /* First sector in file */
unsigned char starthi;
char namelo[8];
char namehi[3];
};
struct atr_head {
unsigned char h0; /* 0x96 */
unsigned char h1; /* 0x02 */
unsigned char seccountlo;
unsigned char seccounthi;
unsigned char secsizelo;
unsigned char secsizehi;
unsigned char hiseccountlo;
unsigned char hiseccounthi;
unsigned char unused[8];
};
/************************************************************************/
/* Function Prototypes */
/************************************************************************/
void write_file(FILE *fin,int sector,int fileno); /* Write a file starting at the specified sector */
void write_dir(int sector); /* Write a directory */
void set_dos_version(char *fname); /* Determine which version of DOS.SYS it is */
int use_sector(void); /* Return a sector number that is free to use after marking it */
int use_8_sector(void); /* Get 8 sectors for a directory */
void write_boot(void); /* Write first 3 sectors */
void write_bitmaps(void); /* Write out the free bitmap */
int afnamecpy(char *an,const char *n);
/************************************************************************/
/* Global variables */
/************************************************************************/
int secsize;
int mydos=0;
int upcase=0;
int debug=0;
int seccount;
char bitmap[64*1024]; /* Free "bit" map */
int lastfree=4;
FILE *fout;
int rootdir; /* flag for sorting routine */
int dos=0; /* true if DOS.SYS is written */
int dosver=0; /* DOS.SYS version code */
/************************************************************************/
/* main() */
/* Process command line */
/* Open input .ATR file */
/* Interpret .ATR header */
/************************************************************************/
int main(int argc,char *argv[])
{
struct atr_head head;
int i;
unsigned char buf[256];
--argc; ++argv; /* Skip program name */
secsize=128;
/* Process flags */
while (argc) {
int done=0;
if (**argv=='-') {
++*argv;
while(**argv) {
switch(**argv) {
case 'd': /* DD */
secsize=256;
break;
case 'm': /* MyDos disk */
mydos=1;
break;
case '-': /* Last option */
done=1;
break;
case 'u': /* strupr names */
upcase=1;
break;
case 'p': /* debugging */
debug=1;
break;
case 's': /* skip early sectors */
lastfree=721;
break;
default:
fprintf(stderr,USAGE);
exit(1);
}
++*argv;
}
--argc; ++argv;
}
else break;
if (done) break;
}
if (argc<2) {
fprintf(stderr,USAGE);
exit(1);
}
/* Number of sectors */
seccount=atoi(*argv);
++argv;--argc;
if (seccount<368) {
fprintf(stderr,USAGE);
exit(1);
}
if ((seccount>1040||(seccount>720&&secsize==256))&&!mydos) {
fprintf(stderr,"Must use MyDos format if more than 1040 SD or 720 DD sectors\n");
exit(1);
}
/* Open output file */
fout=fopen(*argv,"wb");
if (!fout) {
fprintf(stderr,"Unable to open %s\n%s",*argv,USAGE);
exit(1);
}
--argc; ++argv;
/* Change directories? */
if (argc) {
if (chdir(*argv)) {
fprintf(stderr,"Unable to change to directory: %s\n%s",*argv,USAGE);
exit(1);
}
}
/* Initialize free sectors */
for(i=1;i<=seccount;++i) bitmap[i]=0;
for(i=seccount+1;i<64*1024;++i) bitmap[i]=1;
for(i=360;i<=368;++i) bitmap[i]=1;
for(i=0;i<=3;++i) bitmap[i]=1;
if (mydos) {
if (seccount>943+(secsize-128)*8) {
for(i=360-((seccount-943+(secsize*8-1))/(secsize*8));i<360;++i) bitmap[i]=1;
}
}
else {
for(i=1024;i<=seccount;++i) {
bitmap[i]=0; /* Don't use sectors 1024 or above */
}
}
if (!mydos) bitmap[720]=1;
/* Initialize ATR header */
head.h0=0x96;
head.h1=0x02;
head.secsizelo=secsize&0xff;
head.secsizehi=secsize/0x100;
{
unsigned long paragraphs;
paragraphs=(seccount-3)*(secsize/16) + 3*128/16;
head.seccountlo=paragraphs&0xff;
head.seccounthi=(paragraphs>>8)&0xff;
head.hiseccountlo=(paragraphs>>16)&0xff;
head.hiseccounthi=(paragraphs>>24)&0xff;
}
bzero(head.unused,sizeof(head.unused));
fwrite(&head,sizeof(head),1,fout);
/* Initialize sectors */
if (debug)printf("Creating %d %d-byte sectors (%d byte file)\n",seccount,secsize,SEEK(seccount)+secsize);
for(i=0;i<256;++i)buf[i]=0;
fseek(fout,SEEK(1),SEEK_SET);
for(i=1;i<=3;++i) fwrite(buf,128,1,fout);
for(i=4;i<=seccount;++i) fwrite(buf,secsize,1,fout);
write_dir(361);
write_boot();
write_bitmaps();
return(0);
}
/************************************************************************/
/* write_file() */
/* Write a file starting at the specified sector */
/************************************************************************/
void write_file(FILE *fin,int sector,int fileno)
{
unsigned char buf[256];
int i;
int sc=1;
unsigned char c;
c=fgetc(fin);
while (!feof(fin)) {
int nsec=0;
bzero(buf,secsize);
if (!mydos) buf[secsize-3]=(fileno<<2);
for(i=0;i<secsize-3;++i) {
buf[i]=c;
++buf[secsize-1];
c=fgetc(fin);
if (feof(fin)) break;
}
/* Write the sector */
if (!feof(fin)) {
nsec=use_sector();
++sc;
buf[secsize-2]=nsec%256;
buf[secsize-3]+=nsec/256; /* add to fileno */
}
fseek(fout,SEEK(sector),SEEK_SET);
fwrite(buf,secsize,1,fout);
if (nsec && buf[secsize-1]!=secsize-3) {
printf("Something is very wrong!\n");
printf("sector: %d\n",sector);
printf("nsec: %d\n",nsec);
printf("bytes: %d\n",buf[secsize-1]);
exit(1);
}
if (debug && 0) printf("\t\t\tsector %d -> %d\n",sector,nsec);
sector=nsec;
}
if (debug) printf("\t\tFile written, %d sectors\n",sc);
}
/************************************************************************/
/* mydirsort() */
/* */
/* Compare two directory entries for use in sorting. */
/* Essentially alphabetical ordering, except for special files that */
/* go first: DOS.SYS, DUP.SYS, and AUTORUN.SYS. */
/* */
/* Note that MyDOS 4.53 seems to use '*AR0' instead of 'AUTORUN.SYS' */
/* as the auto-loaded menu program. I don't know why. */
/************************************************************************/
int mydirsort(const struct dirent *const*a,const struct dirent *const*b)
{
char an[12],bn[12];
/* If the filename isn't valid for Atari, it's order doesn't matter */
if (!afnamecpy(an,(*a)->d_name)) return(0);
if (!afnamecpy(bn,(*b)->d_name)) return(0);
/* Place certain files first in the root directory */
if (rootdir) {
if (strcmp(an,"DOS SYS")==0) return(-1);
if (strcmp(bn,"DOS SYS")==0) return( 1);
if (strcmp(an,"DUP SYS")==0) return(-1);
if (strcmp(bn,"DUP SYS")==0) return( 1);
if (strcmp(an,"AUTORUN SYS")==0) return(-1);
if (strcmp(bn,"AUTORUN SYS")==0) return( 1);
if (strcmp(an,"AUTORUN AR0")==0) return(-1);
if (strcmp(bn,"AUTORUN AR0")==0) return( 1);
#if 1 /* force some reordering to make me happy */
if (strcmp(an,"FILES LST")==0) return(-1);
if (strcmp(bn,"FILES LST")==0) return( 1);
if (strcmp(an+2,bn+2)==0) return(strcmp(an,bn));
if (strcmp(an+2," ")==0) return( 1);
if (strcmp(bn+2," ")==0) return(-1);
#endif
}
/* Compare the converted filenames */
return(strcmp(an,bn));
}
/************************************************************************/
/* write_dir() */
/************************************************************************/
#define SENTRY(n) (secsize==128?n:(n/8)*8+n)
void write_dir(int sector)
{
struct direct **d;
int used;
int i;
int e;
int count;
int start;
char aname[12];
struct atari_dirent dir[128]; /* 64 + 64 DD wasted space */
int lastfreesave=0;
aname[11]=0;
for(i=0;i<8*256;++i) ((char *)dir)[i]=0;
rootdir=(sector==361);
i=scandir(".",&d,NULL,mydirsort);
used=0;
while (i) {
/* Process **d */
do {
struct stat sbuf;
int subdir;
/* Hidden files--ignore silently */
if ((*d)->d_name[0]=='.') break;
if (lastfreesave) {
lastfree=lastfreesave;
lastfreesave=0;
}
/* Convert name */
if (!afnamecpy(aname,(*d)->d_name)) {
printf("Warning: %s: Can't convert to Atari name\n",(*d)->d_name);
break;
}
/* If it's DOS.SYS, start at sector 4, even if we're reserving the first 720 sectors */
if (rootdir) {
if (strcmp(aname,"DOS SYS")==0) {
set_dos_version((*d)->d_name);
}
if (
strcmp(aname,"DOS SYS")==0 ||
strcmp(aname,"DUP SYS")==0 ||
strcmp(aname,"AUTORUN SYS")==0
) {
lastfreesave=lastfree;
lastfree=3;
}
}
/* Determine if it's a file or directory */
if (stat((*d)->d_name,&sbuf)) {
printf("Warning: %s: Can't stat file\n",(*d)->d_name);
break;
}
subdir=0;
if (!sbuf.st_mode&(S_IFDIR|S_IFREG)) {
printf("Warning: %s: Not a normal file or directory\n",(*d)->d_name);
break;
}
if (sbuf.st_mode&S_IFDIR) subdir=1;
if (subdir && !mydos) {
printf("Warning: %s/: Can't process subdirectory for standard Atari images\n",(*d)->d_name);
break;
}
/* Create the entry */
e=SENTRY(used);
if (used>63) {
printf("Warning: More than 64 files in this directory\n");
printf(" Additional files or subdirectories ignored\n");
return;
}
strcpy(dir[e].namelo,aname);
if (subdir) {
dir[e].flag=16;
count=8;
start=use_8_sector();
}
else {
dir[e].flag=0x46;
if (!sbuf.st_mode&0000200) dir[e].flag &=32; /* locked */
count=(sbuf.st_size+(secsize-3)-1)/(secsize-3);
start=use_sector();
}
dir[e].countlo=count&0xff;
dir[e].counthi=count/0x100;
dir[e].startlo=start&0xff;
dir[e].starthi=start/0x100;
/* Write the directory sector */
fseek(fout,SEEK(sector),SEEK_SET);
fwrite(dir,secsize,8,fout);
++used;
/* Write the file/subdir */
if (!subdir) {
FILE *fin;
fin=fopen((*d)->d_name,"rb");
if (!fin) {
printf("Warning: %s: Can't open file\n",(*d)->d_name);
break;
}
if (debug) printf("\tWriting file %s starting at sector %d\n",(*d)->d_name,start);
write_file(fin,start,used-1);
fclose(fin);
}
else {
if (debug) printf("\tWriting directory %s\n",(*d)->d_name);
if (chdir((*d)->d_name)) {
fprintf(stderr,"Unable to change to directory: %s\n",(*d)->d_name);
break;
}
write_dir(start);
chdir("..");
}
} while(0); /* for break */
free(*d);
++d;--i;
}
}
/************************************************************************/
/* set_dos_version() */
/* Read the first K of dos.sys and make an educated guess as to which */
/* version it is. */
/************************************************************************/
void set_dos_version(char *fname)
{
FILE *dosfile;
unsigned char buf[1024];
dosfile=fopen(fname,"rb");
if (!dosfile) return;
fread(buf,1,1024,dosfile);
fclose(dosfile);
if (buf[18]==0x08) dosver=450; /* MyDOS 4.50 */
if (buf[18]==0xFD) dosver=453; /* MyDOS 4.53/4 */
if (dosver==0) {
printf("Warning: Unable to determine DOS.SYS version\n");
}
dos=1;
}
/************************************************************************/
/* use_sector() */
/* Return a sector number that is free to use after marking it used. */
/************************************************************************/
int use_sector(void)
{
while (lastfree<=seccount&&bitmap[lastfree]) ++lastfree;
if (lastfree>seccount) {
fprintf(stderr,"Disk image full\n");
write_bitmaps();
exit(1);
}
bitmap[lastfree]=1;
return(lastfree);
}
/************************************************************************/
/* use_8_sector() */
/* Get 8 consecutive sectors for a directory */
/************************************************************************/
int use_8_sector(void)
{
int i=lastfree;
int j;
while ((bitmap[i+0]||bitmap[i+1]||bitmap[i+2]||bitmap[i+3]||
bitmap[i+4]||bitmap[i+5]||bitmap[i+6]||bitmap[i+7])
&& i+7<64*1024) ++i;
if (i+7<64*1024) {
for (j=0;j<8;++j) bitmap[i+j]=1;
return(i);
}
fprintf(stderr,"Disk image full--no room for directory\n");
write_bitmaps();
exit(1);
}
/************************************************************************/
/* write_boot() */
/* Write out the first 3 sectors */
/************************************************************************/
void write_boot(void)
{
/*
* Sectors 1 through 3
*
* Copied from a blank 720-sector DOS2.0S-formatted disk
* DOS2.5 generates the same data for 720- and 1040-sector disks.
*
* Writing DOS files may change some bytes, but I haven't checked
* to see which bytes change.
*/
char dos20init[128*3]={
0x00,0x03,0x00,0x07,0x40,0x15,0x4c,0x14,0x07,0x03,0x03,0x00,0x7c,0x1a,0x00,0x04,
0x00,0x7d,0xcb,0x07,0xac,0x0e,0x07,0xf0,0x36,0xad,0x12,0x07,0x85,0x43,0x8d,0x04,
0x03,0xad,0x13,0x07,0x85,0x44,0x8d,0x05,0x03,0xad,0x10,0x07,0xac,0x0f,0x07,0x18,
0xae,0x0e,0x07,0x20,0x6c,0x07,0x30,0x17,0xac,0x11,0x07,0xb1,0x43,0x29,0x03,0x48,
0xc8,0x11,0x43,0xf0,0x0e,0xb1,0x43,0xa8,0x20,0x57,0x07,0x68,0x4c,0x2f,0x07,0xa9,
0xc0,0xd0,0x01,0x68,0x0a,0xa8,0x60,0x18,0xa5,0x43,0x6d,0x11,0x07,0x8d,0x04,0x03,
0x85,0x43,0xa5,0x44,0x69,0x00,0x8d,0x05,0x03,0x85,0x44,0x60,0x8d,0x0b,0x03,0x8c,
0x0a,0x03,0xa9,0x52,0xa0,0x40,0x90,0x04,0xa9,0x57,0xa0,0x80,0x8d,0x02,0x03,0x8c,
0x03,0x03,0xa9,0x31,0xa0,0x0f,0x8d,0x00,0x03,0x8c,0x06,0x03,0xa9,0x03,0x8d,0xff,
0x12,0xa9,0x00,0xa0,0x80,0xca,0xf0,0x04,0xa9,0x01,0xa0,0x00,0x8d,0x09,0x03,0x8c,
0x08,0x03,0x20,0x59,0xe4,0x10,0x1d,0xce,0xff,0x12,0x30,0x18,0xa2,0x40,0xa9,0x52,
0xcd,0x02,0x03,0xf0,0x09,0xa9,0x21,0xcd,0x02,0x03,0xf0,0x02,0xa2,0x80,0x8e,0x03,
0x03,0x4c,0xa2,0x07,0xae,0x01,0x13,0xad,0x03,0x03,0x60,0xaa,0x08,0x14,0x0b,0xbe,
0x0a,0xcb,0x09,0x00,0x0b,0xa6,0x0b,0x07,0x85,0x44,0xad,0x0a,0x07,0x8d,0xd6,0x12,
0xad,0x0c,0x07,0x85,0x43,0xad,0x0d,0x07,0x85,0x44,0xad,0x0a,0x07,0x8d,0x0c,0x13,
0xa2,0x07,0x8e,0x0d,0x13,0x0e,0x0c,0x13,0xb0,0x0d,0xa9,0x00,0x9d,0x11,0x13,0x9d,
0x29,0x13,0x9d,0x31,0x13,0xf0,0x36,0xa0,0x05,0xa9,0x00,0x91,0x43,0xe8,0x8e,0x01,
0x03,0xa9,0x53,0x8d,0x02,0x03,0x20,0x53,0xe4,0xa0,0x02,0xad,0xea,0x02,0x29,0x20,
0xd0,0x01,0x88,0x98,0xae,0x0d,0x13,0x9d,0x11,0x13,0xa5,0x43,0x9d,0x29,0x13,0xa5,
0x44,0x9d,0x31,0x13,0x20,0x70,0x08,0x88,0xf0,0x03,0x20,0x70,0x08,0xca,0x10,0xb2,
0xac,0x09,0x07,0xa2,0x00,0xa9,0x00,0x88,0x10,0x01,0x98,0x9d,0x19,0x13,0x98,0x30,
0x0d,0xa5,0x43,0x9d,0x39,0x13,0xa5,0x44,0x9d,0x49,0x13,0x20,0x70,0x08,0xe8,0xe0,
0x10,0xd0,0xe2,0xa5,0x43,0x8d,0xe7,0x02,0xa5,0x44,0x8d,0xe8,0x02,0x4c,0x7e,0x08,
0x18,0xa5,0x43,0x69,0x80,0x85,0x43,0xa5,0x44,0x69,0x00,0x85,0x44,0x60,0xa0,0x7f
};
/*
* Sectors 1 through 3
*
* Rick D. <rldetlefsen@delphi.com> reported:
> MYDOS will store the same info in the boot sector as any other DOS. This is
> because the OS must use it to locate and load DOS into ram.
> Sector 1, byte offset 0-19 hold the useful info. b14=1=DOS;=0=No DOS,
> B15 & 16=sector to start of DOS, B18 & B19=DOS load address, B9= #file buffers,
> B10=drive bits, and B17=Disp to sector link(effectivly, disk density). The
> rest of the stuff is either in DOS(ramdisk config), or Mydos guese, i.e. >720
> sectors, or double sided.
*
*/
char mydosinit453[3*128]={
0x4d,0x03,0x00,0x07,0xe0,0x07,0x4c,0x14,0x07,0x03,0x09,0x01,0xe8,0x1b,0x02,0x04
,0x00,0xfd,0x0a,0x0b,0xac,0x12,0x07,0xad,0x13,0x07,0x20,0x58,0x07,0xad,0x10,0x07
,0xac,0x0f,0x07,0x18,0xae,0x0e,0x07,0xf0,0x1d,0x20,0x63,0x07,0x30,0x18,0xac,0x11
,0x07,0xb1,0x43,0x29,0xff,0x48,0xc8,0x11,0x43,0xf0,0x0e,0xb1,0x43,0x48,0x20,0x4d
,0x07,0x68,0xa8,0x68,0x90,0xdd,0xa9,0xc0,0xa0,0x68,0x0a,0xa8,0x60,0xad,0x11,0x07
,0x18,0x65,0x43,0xa8,0xa5,0x44,0x69,0x00,0x84,0x43,0x85,0x44,0x8c,0x04,0x03,0x8d
,0x05,0x03,0x60,0x8d,0x0b,0x03,0x8c,0x0a,0x03,0xa0,0x03,0xa9,0x52,0x90,0x02,0xa9
,0x50,0x84,0x48,0x8d,0x02,0x03,0x18,0x8c,0x06,0x03,0xa9,0x80,0xca,0xf0,0x0d,0xae
,0x0b,0x03,0xd0,0x07,0xae,0x0a,0x03,0xe0,0x04,0x90,0x01,0x0a,0x8d,0x08,0x03,0x2a
,0x8d,0x09,0x03,0xa0,0x31,0x8c,0x00,0x03,0xc6,0x48,0x30,0x16,0xae,0x02,0x03,0xe8
,0x8a,0xa2,0x40,0x29,0x06,0xd0,0x02,0xa2,0x80,0x8e,0x03,0x03,0x20,0x59,0xe4,0x88
,0x30,0xe6,0xa6,0x2e,0xc8,0x98,0x60,0x10,0x69,0x01,0x00,0x80,0xf6,0x00,0x00,0x00
,0x23,0x28,0x50,0x4d,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x12,0x52,0xd2,0xd2
,0xd2,0xd2,0xd2,0xd2,0x5c,0x0c,0x5c,0x0e,0x62,0x0d,0xc6,0x0d,0x50,0x0e,0x67,0x10
,0xa9,0x69,0x8d,0xb8,0x07,0xa9,0x01,0x8d,0xb9,0x07,0xa2,0x08,0x8e,0x01,0x03,0x20
,0xb6,0x0b,0xbd,0xcb,0x07,0x30,0x12,0x20,0x9a,0x0b,0xf0,0x0d,0xbd,0xcb,0x07,0xc9
,0x40,0xb0,0x06,0xbc,0xc3,0x07,0x20,0x24,0x0b,0xca,0xd0,0xe0,0xa0,0xae,0x8a,0x99
,0x55,0x08,0x88,0xd0,0xfa,0xee,0x59,0x08,0xad,0x0c,0x07,0x8d,0xe7,0x02,0xac,0x0d
,0x07,0xa2,0x0f,0xec,0x09,0x07,0x90,0x05,0xde,0xdd,0x08,0x30,0x05,0x98,0x9d,0xed
,0x08,0xc8,0xca,0x10,0xee,0x8c,0xe8,0x02,0xe8,0xe8,0xe8,0xbd,0x18,0x03,0xf0,0x04
,0xc9,0x44,0xd0,0xf4,0xa9,0x44,0x9d,0x18,0x03,0xa9,0xd4,0x9d,0x19,0x03,0xa9,0x07
,0x9d,0x1a,0x03,0x4c,0x79,0x1a,0x00,0x00,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x80
,0xfd,0x00,0x03,0x04,0x00,0x00,0x00,0x00,0x00,0x69,0x01,0x00,0x00,0x00,0x00,0x00
};
char mydosinit450[3*128]={
0x4d,0x03,0x00,0x07,0xe0,0x07,0x4c,0x14,0x07,0x03,0xff,0x01,0xe9,0x1b,0x02,0x04
,0x00,0xfd,0x15,0x0b,0xac,0x12,0x07,0xad,0x13,0x07,0x20,0x58,0x07,0xad,0x10,0x07
,0xac,0x0f,0x07,0x18,0xae,0x0e,0x07,0xf0,0x1d,0x20,0x63,0x07,0x30,0x18,0xac,0x11
,0x07,0xb1,0x43,0x29,0xff,0x48,0xc8,0x11,0x43,0xf0,0x0e,0xb1,0x43,0x48,0x20,0x4d
,0x07,0x68,0xa8,0x68,0x90,0xdd,0xa9,0xc0,0xa0,0x68,0x0a,0xa8,0x60,0xad,0x11,0x07
,0x18,0x65,0x43,0xa8,0xa5,0x44,0x69,0x00,0x84,0x43,0x85,0x44,0x8c,0x04,0x03,0x8d
,0x05,0x03,0x60,0x8d,0x0b,0x03,0x8c,0x0a,0x03,0xa0,0x03,0xa9,0x52,0x90,0x03,0xad
,0x79,0x07,0x84,0x48,0x8d,0x02,0x03,0x18,0xa9,0x57,0x8c,0x06,0x03,0xa9,0x80,0xca
,0xf0,0x0d,0xae,0x0b,0x03,0xd0,0x07,0xae,0x0a,0x03,0xe0,0x04,0x90,0x01,0x0a,0x8d
,0x08,0x03,0x2a,0x8d,0x09,0x03,0xa0,0x31,0x8c,0x00,0x03,0xc6,0x48,0x30,0x16,0xae
,0x02,0x03,0xe8,0x8a,0xa2,0x40,0x29,0x06,0xd0,0x02,0xa2,0x80,0x8e,0x03,0x03,0x20
,0x59,0xe4,0x88,0x30,0xe6,0xa6,0x2e,0xc8,0x98,0x60,0x10,0x71,0x01,0x00,0x80,0xf6
,0x23,0x28,0x50,0x4d,0x01,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x52,0x12,0xd2,0xd2
,0xd2,0xd2,0xd2,0xd2,0x5c,0x0c,0x5c,0x0e,0x62,0x0d,0xc6,0x0d,0x50,0x0e,0x67,0x10
,0xa9,0x69,0x8d,0xbb,0x07,0xa9,0x01,0x8d,0xbc,0x07,0xa2,0x08,0x8e,0x01,0x03,0x20
,0xb6,0x0b,0xbd,0xcb,0x07,0x30,0x1d,0x20,0x9a,0x0b,0xf0,0x18,0xa0,0x09,0xb9,0x25
,0x0b,0x99,0x02,0x03,0x88,0x10,0xf7,0xbd,0xcb,0x07,0xc9,0x40,0xb0,0x06,0xbc,0xc3
,0x07,0x20,0x2f,0x0b,0xca,0xd0,0xd5,0xa0,0xae,0x8a,0x99,0x60,0x08,0x88,0xd0,0xfa
,0xee,0x64,0x08,0xad,0x0c,0x07,0x8d,0xe7,0x02,0xac,0x0d,0x07,0xa2,0x0f,0xec,0x09
,0x07,0x90,0x05,0xde,0xe8,0x08,0x30,0x05,0x98,0x9d,0xf8,0x08,0xc8,0xca,0x10,0xee
,0x8c,0xe8,0x02,0xe8,0xe8,0xe8,0xbd,0x18,0x03,0xf0,0x04,0xc9,0x44,0xd0,0xf4,0xa9
,0x44,0x9d,0x18,0x03,0xa9,0xd4,0x9d,0x19,0x03,0xa9,0x07,0x9d,0x1a,0x03,0x4c,0x8c
,0x1a,0x00,0x00,0xff,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc8,0x80,0xfd,0x00,0x03,0x04,0x00
};
char *mydosinit;
if (debug && mydos) {
printf("Mydos version: %d\n",dosver);
}
switch (dosver) {
case 450:
mydosinit=mydosinit450;
break;
case 453:
mydosinit=mydosinit453;
break;
default:
mydosinit=mydosinit450;
if (mydos && dos) {
printf("Warning: Failed to detect MyDOS version, may not boot\n");
}
}
mydosinit[0]='M'; /* Indicate MyDOS 4.5 or later */
mydosinit[1]=3; /* number of sectors in the boot */
mydosinit[9]=3; /* Max number of open files at one time */
mydosinit450[10]=255; /* Ram Disk unit number */
mydosinit453[10]=9; /* Ram Disk unit number */
mydosinit[11]=1; /* Default unit number (D:) */
/* [12],[13]: First byte of free memory */
mydosinit[14]=((secsize==256)?2:1);
mydosinit[15]=4;mydosinit[16]=0; /* DOS.SYS start sector */
mydosinit[17]=secsize-3; /* Offset to the sector link field */
/* [18],[19]: Address to load dos.sys into */
if (dos) {
mydosinit450[18]=21;
mydosinit453[18]=10;
}
/*
* The following seemed to be correct based on experimentation:
*/
mydosinit453[196]=((secsize==256)?2:1);
mydosinit453[368]=secsize-3;
fseek(fout,SEEK(1),SEEK_SET);
fwrite(mydos?mydosinit:dos20init,128,3,fout);
}
/************************************************************************/
/* write_bitmaps() */
/* Write out the free bitmap (VTOC) */
/* I'm a bit clueless on much of this, but it tries to do what I've */
/* observed from real disk images. */
/************************************************************************/
void write_bitmaps(void)
{
char sec360[256] /******** ={
0x02,0xc3,0x02,0xc3,0x02,0x00,0x00,0x00,0x00,0x00,0x0f,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
}********/;
int i;
int byte,bit;
int free;
for(i=0;i<256;++i)sec360[i]=0;
/*
* We need to clean up the computation of total data sectors.
*
* For non-MyDos>720, we need to take into account the second VTOC
* For MyDos, we need to count 720, but not additional VTOC sectors.
*/
{
int total;
total=seccount-3-9-1; /* Boot, VTOC+DIR, 720 */
if (mydos) {
total=seccount-3-8; /* boot and dir */
total-=(1+(seccount-(943+(secsize-128)*8)+(secsize*8-1))/(secsize*8)); /* VTOC */
}
else if (seccount>720) {
if (total>1023-3-8-1-1) total=1023-3-8-1-1;
}
sec360[2]=(total)/256;
sec360[1]=(total)%256;
}
/*
* Record the number of free sectors
* For DOS2.5, this is the number of free sectors in this VTOC.
*/
free=0;
for(i=0;i<=(mydos?seccount:720);++i) {
if (bitmap[i]==0) ++free;
}
sec360[4]=free/256;
sec360[3]=free%256;
if (debug) {
printf("%d sectors %sfree\n",free,mydos?"":"<720 ");
}
/*
* I'm clueless--is this some sort of version code?
* I think this agrees with how MyDOS and DOS2.5 set this byte.
*/
sec360[0]=2;
if (mydos && seccount>943) sec360[0]+=(seccount-943+(secsize*8-1))/(secsize*8)+1;
/*
* bitmap[i] is true if the sector has been used
*
* The corresponding bit should be one if the sector is *free*
*/
if (!mydos) {
for(i=0;i<720;++i) {
byte=10+i/8;
bit=i%8;
bit=7-bit;
bit=1<<bit;
if(bitmap[i]) {
sec360[byte]&= ~bit;
}
else {
sec360[byte]|=bit;
}
}
/* Write sector 360 */
fseek(fout,SEEK(360),SEEK_SET);
fwrite(sec360,128,1,fout);
if(seccount>720) {
/* Copy most of first VTOC */
for(i=0;i<128-16;++i)sec360[i]=sec360[i+16];
free=0;
for(i=720;i<1024;++i) {
byte=i/8-6;
bit=i%8;
bit=7-bit;
bit=1<<bit;
if(bitmap[i]) {
sec360[byte]&= ~bit;
++free;
}
else {
sec360[byte]|=bit;
}
}
/* Record number of free extended sectors */
sec360[123]=free/256;
sec360[122]=free%256;
fseek(fout,SEEK(1024),SEEK_SET);
fwrite(sec360,128,1,fout);
}
}
else {
for(i=0;i<=943;++i) {
byte=10+i/8;
bit=i%8;
bit=7-bit;
bit=1<<bit;
if(bitmap[i]) {
sec360[byte]&= ~bit;
}
else {
sec360[byte]|=bit;
}
}
/* Write sector 360 */
fseek(fout,SEEK(360),SEEK_SET);
fwrite(sec360,128,1,fout);
if(seccount>943) {
int ss;
int sn=359;
for(ss=944;ss<=seccount;ss+=8*128,--sn) {
for(i=0;i<128;++i)sec360[i]=0;
for(i=0;i<8*128;++i) {
byte=i/8;
bit=i%8;
bit=7-bit;
bit=1<<bit;
if(bitmap[i+ss]) {
sec360[byte]&= ~bit;
}
else {
sec360[byte]|=bit;
}
}
/* Write sector */
{
int s,o;
if (secsize==128) {
s=sn;
o=0;
}
else {
/*
* Hack for DD sectors
*/
s=360-sn;
o=(s&1)*128;
s=s/2;
s=360-s;
}
fseek(fout,SEEK(s)+o,SEEK_SET);
fwrite(sec360,128,1,fout);
}
}
}
}
}
/************************************************************************/
/* afnamecpy() */
/* Convert a Unix filename to an Atari filename. */
/* Return 0 on failure. */
/************************************************************************/
int afnamecpy(char *an,const char *n)
{
int i;
for(i=0;i<11;++i) an[i]=' '; /* Space fill the Atari name */
an[11]=0;
for(i=0;i<8;++i) {
if (!*n) return(1); /* Ok */
if (*n=='.') break; /* Extension */
if (*n==':') return(0); /* Illegal name */
if (upcase) an[i]=toupper(*n);
else an[i]= *n;
++n;
}
if (*n=='.') ++n;
for(i=8;i<11;++i) {
if (!*n) return(1); /* Ok */
if (*n=='.') return(0); /* Illegal name */
if (*n==':') return(0); /* Illegal name */
if (upcase) an[i]=toupper(*n);
else an[i]= *n;
++n;
}
if (*n) return(0); /* Extension too long or more than 11 characters */
return(1);
}