From 40cdea9b8d0aa5339bc2914787789bb55e8eccdb Mon Sep 17 00:00:00 2001 From: Michaelangel007 Date: Wed, 27 Jan 2016 16:35:32 -0800 Subject: [PATCH] Add bin/ directory --- bin/a2tools.c | 845 +++++++++++++++++++++++++++++++++++++++++++++ bin/apple2bin.cfg | 9 + bin/dos33.inc | 4 + bin/emptydos33.dsk | Bin 0 -> 143360 bytes bin/src2dsk.sh | 152 ++++++++ 5 files changed, 1010 insertions(+) create mode 100644 bin/a2tools.c create mode 100644 bin/apple2bin.cfg create mode 100644 bin/dos33.inc create mode 100755 bin/emptydos33.dsk create mode 100755 bin/src2dsk.sh diff --git a/bin/a2tools.c b/bin/a2tools.c new file mode 100644 index 0000000..4e7c440 --- /dev/null +++ b/bin/a2tools.c @@ -0,0 +1,845 @@ +/* + + a2tools - utilities for transferring data between Unix and Apple II + DOS 3.3 disk images. + + Copyright (C) 1998, 2001 Terry Kyriacopoulos + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + Author's e-mail address: terryk@echo-on.net + + ------------------------------------------------------------------- + + Cleaned up abuse of C semantics to compile clean + Replaced original line #820 (now line #831) + while(i<30 && a2_name[i]) padded_name[i]=a2_name[i++] & 0x7f; + With: + while(i<30 && a2_name[i]) { padded_name[i]=a2_name[i] & 0x7f; i++; } + Michael Pohoreski, Jan 16, 2016 + + ------------------------------------------------------------------- + + Modified to be more portable: Unix specifics are marked as such. + ANSI-C is assumed, code is now acceptable to C++ as well, + type definitions are straighetend up, unused variables are removed, + casts are added when required by C++. + + Paul Schlyter, 2001-03-20, pausch@saaf.se + + ------------------------------------------------------------------- + + Improvements to accomodate MS-DOS have been made: + + - code fixed to work properly on a 16-bit platform + - conditional compilation used to select OS-specific code + automatically + - user interface is now more OS-specific: + - argv[0] command selection for UNIX, argv[1] for DOS + - stdin/stdout forbidden on binary data in DOS + - optional source/destination pathnames for in/out commands + - improved documentation + + Terry Kyriacopoulos, April 8, 2001 terryk@echo-on.net + + +*/ + +#ifndef UNIX + #ifdef __unix__ + #define UNIX + #endif +#endif +#ifndef DOS + #ifdef __MSDOS__ + #define DOS + #endif +#endif + +#ifndef UNIX + #ifndef DOS + #error Please define macro UNIX or DOS. + #endif +#else + #ifdef DOS + #error Both macros UNIX and DOS are defined! + #endif +#endif + +#ifdef DOS +const char *const DOS_HelpText = + +"\n" +"a2tools - utility for transferring files from/to Apple II .dsk images\n" +" Copyright (C) 1998, 2001 Terry Kyriacopoulos\n" +" Copyright (C) 2001 Paul Schlyter\n" +" Copyright (C) 2016 Michael Pohoreski\n" +"\n" +" Usage:\n" +"\n" +" a2 dir \n" +" a2 out [-r] []\n" +" a2 in [-r] [.] []\n" +" a2 del \n" +"\n" +" -r (raw mode): Suppress all filetype-dependent processing\n" +" and copy everything as-is.\n" +"\n" +" : one of t,i,a,b,s,r,x,y (do not use -)\n" +" : base address in hex, for type B (binary)\n" +"\n" +" Quotes may be used around names with spaces, use \\\"\n" +" to include a quote in the name.\n" +; +#endif + +/* Apple Integer and AppleSoft BASIC tokens. */ + +const char *const Integer_tokens[] = { + +" HIMEM:", "", " _ ", ":", +" LOAD ", " SAVE ", " CON ", " RUN ", +" RUN ", " DEL ", ",", " NEW ", +" CLR ", " AUTO ", ",", " MAN ", +" HIMEM:", " LOMEM:", "+", "-", +"*", "/", "=", "#", +">=", ">", "<=", "<>", +"<", " AND ", " OR ", " MOD ", +" ^ ", "+", "(", ",", +" THEN ", " THEN ", ",", ",", +"\"", "\"", "(", "!", +"!", "(", " PEEK ", " RND ", +" SGN ", " ABS ", " PDL ", " RNDX ", +"(", "+", "-", " NOT ", +"(", "=", "#", " LEN(", +" ASC(", " SCRN(", ",", "(", + +"$", "$", "(", ",", +",", ";", ";", ";", +",", ",", ",", " TEXT ", +" GR ", " CALL ", " DIM ", " DIM ", +" TAB ", " END ", " INPUT ", " INPUT ", +" INPUT ", " FOR ", "=", " TO ", +" STEP ", " NEXT ", ",", " RETURN ", +" GOSUB ", " REM ", " LET ", " GOTO ", +" IF ", " PRINT ", " PRINT ", " PRINT ", +" POKE ", ",", " COLOR=", " PLOT ", +",", " HLIN ", ",", " AT ", +" VLIN ", ",", " AT ", " VTAB ", +"=", "=", ")", ")", +" LIST ", ",", " LIST ", " POP ", +" NODSP ", " NODSP ", " NOTRACE ", " DSP ", +" DSP ", " TRACE ", " PR#", " IN#" + +}; + + +const char *const Applesoft_tokens[] = { + +" END ", " FOR ", " NEXT ", " DATA ", +" INPUT ", " DEL ", " DIM ", " READ ", +" GR ", " TEXT ", " PR#", " IN#", +" CALL ", " PLOT ", " HLIN ", " VLIN ", +" HGR2 ", " HGR ", " HCOLOR=", " HPLOT ", +" DRAW ", " XDRAW ", " HTAB ", " HOME ", +" ROT=", " SCALE=", " SHLOAD ", " TRACE ", +" NOTRACE ", " NORMAL ", " INVERSE ", " FLASH ", +" COLOR=", " POP ", " VTAB ", " HIMEM:", +" LOMEM:", " ONERR ", " RESUME ", " RECALL ", +" STORE ", " SPEED=", " LET ", " GOTO ", +" RUN ", " IF ", " RESTORE ", " & ", +" GOSUB ", " RETURN ", " REM ", " STOP ", +" ON ", " WAIT ", " LOAD ", " SAVE ", +" DEF ", " POKE ", " PRINT ", " CONT ", +" LIST ", " CLEAR ", " GET ", " NEW ", + +" TAB(", " TO ", " FN ", " SPC(", +" THEN ", " AT ", " NOT ", " STEP ", +" + ", " - ", " * ", " / ", +" ^ ", " AND ", " OR ", " > ", +" = ", " < ", " SGN ", " INT ", +" ABS ", " USR ", " FRE ", " SCRN(", +" PDL ", " POS ", " SQR ", " RND ", +" LOG ", " EXP ", " COS ", " SIN ", +" TAN ", " ATN ", " PEEK ", " LEN ", +" STR$ ", " VAL ", " ASC ", " CHR$ ", +" LEFT$ ", " RIGHT$ ", " MID$ ", " ", + +" SYNTAX ", " RETURN WITHOUT GOSUB ", +" OUT OF DATA ", " ILLEGAL QUANTITY ", +" OVERFLOW ", " OUT OF MEMORY ", +" UNDEF'D STATEMENT ", " BAD SUBSCRIPT ", +" REDIM'D ARRAY ", " DIVISION BY ZERO ", +" ILLEGAL DIRECT ", " TYPE MISMATCH ", +" STRING TOO LONG ", " FORMULA TOO COMPLEX ", +" CAN'T CONTINUE ", " UNDEF'D FUNCTION ", + +" ERROR \a", "", "", "" + +}; + +#include +#include +#include +#include + +#define FILETYPE_T 0x00 +#define FILETYPE_I 0x01 +#define FILETYPE_A 0x02 +#define FILETYPE_B 0x04 +#define FILETYPE_S 0x08 +#define FILETYPE_R 0x10 +#define FILETYPE_X 0x20 +#define FILETYPE_Y 0x40 +/* X - "new A", Y - "new B" */ + +#define MAX_HOPS 560 + +#define VTOC_CHK_NO 6 +const unsigned char vtoc_chk_offset[VTOC_CHK_NO] = + { 0x03, 0x27, 0x34, 0x35, 0x36, 0x37}; +const unsigned char vtoc_chk_value[VTOC_CHK_NO] = + { 0x03, 0x7a, 0x23, 0x10, 0x00, 0x01}; + +FILE *from_file=NULL, *to_file=NULL, *image_fp=NULL; +char *extfilename, *extfilemode; + +unsigned char padded_name[30], dir_entry_data[35]; +unsigned char vtocbuffer[256]; +unsigned int begun, baseaddress, rawmode, filetype, new_sectors; +unsigned long dir_entry_pos; + +void quit(int exitcode, const char *exitmsg) { // const + fprintf(stderr,"%s",exitmsg); + if (image_fp) fclose(image_fp); + if (from_file) fclose(from_file); + if (to_file) fclose(to_file); + exit(exitcode); + } + +int seek_sect (unsigned int track, unsigned int sector) { + if (track >= 35 || sector >= 16) + quit(1,"seek on .dsk out of range.\n"); + return fseek(image_fp, (track*16uL+sector)*256, SEEK_SET); + } + +void read_sect (int track, int sector, unsigned char buffer[256]) { + int i; + seek_sect(track, sector); + for (i=0; i<256; i++) buffer[i]=fgetc(image_fp); + } + +void write_sect (int track, int sector, unsigned char buffer[256]) { + int i; + seek_sect(track, sector); + for (i=0; i<256; i++) fputc(buffer[i],image_fp); + } + +int dir_do (int (*what_to_do)(unsigned char *) ) { + unsigned char buffer[256]; + unsigned int cur_trk, cur_sec, i, found, hop; + hop=found=0; + buffer[1]=vtocbuffer[1]; + buffer[2]=vtocbuffer[2]; + while(++hop < MAX_HOPS && !found && (buffer[1] || buffer[2])) { + cur_trk=buffer[1]; + cur_sec=buffer[2]; + read_sect (buffer[1],buffer[2],buffer); + i=0x0b; + while(i<=0xdd && !(found=(*what_to_do)(&buffer[i]))) i+=35; + if (found) dir_entry_pos=(cur_trk*16uL+cur_sec)*256+i; + } + if (hop >= MAX_HOPS) quit(2,"\n***Corrupted directory\n\n"); + return found; + } + +int dir_find_name(unsigned char *buffer) { + int j; + j=0; + if (buffer[0] == 0xff || buffer[3] == 0) return 0; + while(j<30 && padded_name[j]==(buffer[j+3] & 0x7f)) j++; + if (j != 30) return 0; + for (j=0; j<35; j++) dir_entry_data[j]=buffer[j]; + return 1; + } + +int dir_find_space(unsigned char *buffer) { + return (buffer[0] == 0xff || buffer[3] ==0); + } + +int dir_print_entry(unsigned char *buffer) { + int j; + if (buffer[0]!=0xff && buffer[3]!=0) { + /* entry is present */ + printf(" "); + if (buffer[2] & 0x80) printf("*"); else printf(" "); + switch(buffer[2] & 0x7f) { + case FILETYPE_T : printf("T"); break; + case FILETYPE_I : printf("I"); break; + case FILETYPE_A : printf("A"); break; + case FILETYPE_B : printf("B"); break; + case FILETYPE_S : printf("S"); break; + case FILETYPE_R : printf("R"); break; + case FILETYPE_X : printf("X"); break; + case FILETYPE_Y : printf("Y"); break; + default : printf("?"); + } + printf(" %03u ",buffer[33]+buffer[34]*256u); + for (j=3; j<33; j++) + printf("%c",(buffer[j] & 0x7f)); + printf("\n"); + } + return 0; + } + +int preproc (int procmode) { + /* procmode: 0 - raw, 1 - text, 2 -binary */ + static unsigned long bytepos, lengthspec_pos; + static int c; + unsigned int sect_pos; + sect_pos=0; + if (!begun) { + begun = 1; + bytepos = 0; + c=fgetc(from_file); + if (procmode == 2) { + fputc((baseaddress & 0xff),image_fp); + fputc((baseaddress >> 8),image_fp); + /* we don't know the length now, so save the spot in the image */ + lengthspec_pos=ftell(image_fp); + fputc(0xff,image_fp); + fputc(0xff,image_fp); + sect_pos = 4; + } + } + while (c != EOF && sect_pos < 256) { + if (procmode == 1) { + if ((c & 0x7f) == '\n') c = '\r'; + c |= 0x80; + } + fputc(c,image_fp); + c=fgetc(from_file); + sect_pos++; + bytepos++; + } + while (sect_pos++ < 256) fputc(0,image_fp); + if (c == EOF && procmode == 2) { + /* now we know the length */ + fseek(image_fp, lengthspec_pos, SEEK_SET); + fputc((bytepos & 0xff),image_fp); + fputc((bytepos >> 8),image_fp); + } + return (c == EOF); + } + +void new_sector(unsigned int *track, unsigned int *sector) { + /* find a free sector, quit if no more */ + unsigned int byteoffset, bitmask; + int lasttrack, cur_track, cur_sector, direction; + /* force sane values, in case vtoc contains garbage */ + if (vtocbuffer[0x31]==1) direction=1; else direction=-1; + cur_track=lasttrack=vtocbuffer[0x30] % 35u; + cur_sector=15; + for (;;) { + byteoffset=0x39+(cur_track<<2)-(cur_sector>>3&1); + bitmask=(1 <<(cur_sector & 0x07)); + if (vtocbuffer[byteoffset] & bitmask) { + vtocbuffer[byteoffset]&=0xff^bitmask; + break; + } + else if (!cur_sector--) { + cur_sector=15; + cur_track+=direction; + if (cur_track >= 35) { + cur_track=17; + direction=-1; + } + else if (cur_track < 0) { + cur_track=18; + direction=1; + } + if (cur_track==lasttrack) quit(3,"Disk Full.\n"); + } + } + *track=vtocbuffer[0x30]=cur_track; + *sector=cur_sector; + vtocbuffer[0x31]=direction % 256u; + new_sectors++; + } + +void free_sector(int track, int sector) { + vtocbuffer[0x39+(track<<2)-(sector>>3&1)]|=1<<(sector&0x07); + } + +void postproc_B (void) { + static unsigned int filelength, bytepos; + unsigned int sect_pos; + sect_pos=0; + if (!begun) { + begun = 1; + bytepos = 0; + fgetc(image_fp); /* Ignore 2 byte base address */ + fgetc(image_fp); + filelength= fgetc(image_fp) + (fgetc(image_fp) * 256u); + sect_pos = 4; + } + while (bytepos < filelength && sect_pos < 256) { + fputc(fgetc(image_fp),to_file); + sect_pos++; + bytepos++; + } + } + +void postproc_A (void) { + static unsigned int bufstat, tokens_left, lastspot; + static unsigned char lineheader[4]; + unsigned int sect_pos, c; + sect_pos=0; + if (!begun) { /* first sector, initialize */ + begun = 1; + fgetc(image_fp); /* ignore the length data, we use */ + fgetc(image_fp); /* null line pointer as EOF */ + sect_pos = 2; + lastspot = 0x0801; /* normal absolute beginning address */ + tokens_left = bufstat = 0; + } + while(lastspot && sect_pos < 256) { + if (!tokens_left && !bufstat) bufstat = 4; + while (bufstat > 0 && sect_pos < 256) { + lineheader[4-bufstat]=fgetc(image_fp); + sect_pos++; + bufstat--; + } + if (!tokens_left && !bufstat && + (lastspot=lineheader[0]+lineheader[1]*256u)) { + tokens_left = 1; + fprintf(to_file,"\n"); + fprintf(to_file," %u ",lineheader[2]+lineheader[3]*256u); + } + while (tokens_left && lastspot && sect_pos < 256) { + if ((tokens_left=c=fgetc(image_fp)) & 0x80) + fprintf(to_file,"%s",Applesoft_tokens[(c & 0x7f)]); + else if (c) fprintf(to_file,"%c",c); + sect_pos++; + } + } + if (!lastspot) fprintf(to_file,"\n\n"); + } + +void postproc_I (void) { + static unsigned int filelength, bytepos; + static unsigned int bufstat, inputmode, quotemode, varmode; + static unsigned char numbuf[3]; + unsigned int sect_pos, c; + sect_pos=0; + if (!begun) { /* first sector, initialize */ + begun = 1; + filelength = fgetc(image_fp) + (fgetc(image_fp) * 256u); + sect_pos = 2; + bytepos = inputmode = bufstat = quotemode = varmode = 0; + } + /* inputmode: 0 - header, 1 - integer, 2 - tokens */ + /* varmode: 1 means we are in the middle of an identifier */ + while(bytepos < filelength && sect_pos < 256) { + if (inputmode < 2 && !bufstat) bufstat = 3 - inputmode; + while (bufstat > 0 && bytepos < filelength && sect_pos < 256) { + numbuf[3-bufstat]=fgetc(image_fp); + sect_pos++; + bytepos++; + bufstat--; + } + if (!bufstat && inputmode == 0) { + fprintf(to_file,"\n"); + fprintf(to_file,"%5u ",numbuf[1]+(numbuf[2]*256u)); + inputmode = 2; + } + if (!bufstat && inputmode == 1) { + fprintf(to_file,"%u",numbuf[1]+(numbuf[2]*256u)); + inputmode = 2; + } + while (inputmode == 2 && bytepos < filelength && sect_pos < 256) { + c=fgetc(image_fp); + sect_pos++; + bytepos++; + /* 0x28: open quote, 0x29: close quote, 0x5d: REM token */ + if (c == 0x28 || c == 0x5d) quotemode = 1; + if (c == 0x29) quotemode = 0; + /* Look for integer, unless in comment, string, or identifier */ + if (!quotemode && !varmode && c >= 0xb0 && c <= 0xb9) + inputmode = 1; + else { + /* Identifiers begin with letter, may contain digit */ + varmode = (c >= 0xc1 && c <= 0xda) || + ((c >= 0xb0 && c <= 0xb9) && varmode); + if (c == 0x01) inputmode = quotemode = 0; + else if (c & 0x80) fprintf(to_file,"%c",(c & 0x7f)); + else fprintf(to_file,"%s",Integer_tokens[c]); + } + } + } + if (bytepos >= filelength) fprintf(to_file,"\n\n"); + } + +void postproc_T (void) { + static unsigned int not_eof; + unsigned int sect_pos, c; + sect_pos=0; + if (!begun) begun = not_eof = 1; + while (not_eof && sect_pos < 256 && + (not_eof=c=fgetc(image_fp))) { + c &= 0x7f; + if (c == '\r') c='\n'; + fputc(c,to_file); + sect_pos++; + } + } + +void postproc_raw (void) { + unsigned int sect_pos; + for (sect_pos=0; sect_pos < 256; sect_pos++) + fputc(fgetc(image_fp),to_file); + } + +void a2ls (void) { + unsigned int trkmap, free_sect, i, j; + free_sect = 0; + + /* count the free sectors */ + for (i=0x38; i<=0xc0; i+=4) { + trkmap=vtocbuffer[i]*256u + vtocbuffer[i+1]; + for (j=0; j<16; j++) free_sect += ((trkmap & (1<= MAX_HOPS) quit(5,"Corrupted sector list\n\n"); + write_sect(0x11, 0, vtocbuffer); + } + +void a2out (void) { + unsigned char listbuffer[256]; + unsigned int hop, next_trk, next_sec, i, j; + void (*postproc_function)(void); + if (!dir_do(dir_find_name)) quit(6,"File not found.\n"); + hop = begun = 0; + next_trk=dir_entry_data[0]; + next_sec=dir_entry_data[1]; + filetype=(dir_entry_data[2] & 0x7f); + + if (filetype == FILETYPE_T) postproc_function= postproc_T; + else if (filetype == FILETYPE_B) postproc_function= postproc_B; + else if (filetype == FILETYPE_A) postproc_function= postproc_A; + else if (filetype == FILETYPE_I) postproc_function= postproc_I; + else if (!rawmode) + quit(7,"File type supported in raw mode only.\n"); + if (rawmode) postproc_function= postproc_raw; + +#ifdef DOS + extfilemode="w"; + if (rawmode || filetype == FILETYPE_B) { + extfilemode="wb"; + if (to_file) + quit(8,"stdout not allowed for binary output.\n"); + } +#else + extfilemode="w"; +#endif + + if (!to_file && !(to_file=fopen(extfilename,extfilemode))) { + perror(extfilename); + quit(9,""); + } + + while(++hop < MAX_HOPS && (next_trk || next_sec)) { + read_sect(next_trk, next_sec, listbuffer); + next_trk=listbuffer[1]; + next_sec=listbuffer[2]; + for (i=0x0c; i <= 0xfe; i+=2) + if (!listbuffer[i] && !listbuffer[i+1]) { + if (filetype != FILETYPE_T || !rawmode) { + next_trk=next_sec=0; + break; + } + else for (j=0; j<256; j++) fputc(0,to_file); + } + else { + ++hop; + seek_sect(listbuffer[i],listbuffer[i+1]); + (*postproc_function) (); + } + } + if (hop >= MAX_HOPS) quit(10,"Corrupted sector list\n\n"); + + fclose(to_file); + } + +void a2in (void) { + unsigned char listbuffer[256], databuffer[256]; + unsigned int i, curlist_trk, curlist_sec, listentry_pos, list_no; + unsigned int curdata_trk, curdata_sec, procmode; + unsigned int newlist_trk, newlist_sec; + int c; + new_sectors=list_no=procmode=0; + if (!rawmode) { + if (filetype==FILETYPE_T) procmode=1; + else if (filetype==FILETYPE_B) procmode=2; + else quit(11,"This type is supported only in raw mode.\n"); + } + +#ifdef DOS + extfilemode="r"; + if (procmode !=1) { + extfilemode="rb"; + if (from_file) + quit(12,"stdin not allowed for binary input.\n"); + } +#else + extfilemode="r"; +#endif + + if (!from_file && !(from_file=fopen(extfilename,extfilemode))) { + perror(extfilename); + quit(13,""); + } + + if (dir_do(dir_find_name)) quit(14,"File exists.\n"); + if (!dir_do(dir_find_space)) quit(15,"No space in directory.\n"); + if (padded_name[0] < 'A') + quit(16,"Bad first filename character, must be >= 'A'.\n"); + for (i=0;i<30;i++) + if (padded_name[i]==',') + quit(17,"Filename must not contain a comma.\n"); + for (i=0;i<30;i++) dir_entry_data[i+3]=padded_name[i]|0x80; + dir_entry_data[2]=filetype; + + new_sector(&curlist_trk,&curlist_sec); + dir_entry_data[0]=curlist_trk; + dir_entry_data[1]=curlist_sec; + for (i=0;i<256;i++) listbuffer[i]=0; + listentry_pos=0; + + for (;;) { + if (!rawmode || filetype!=FILETYPE_T) { + new_sector(&curdata_trk,&curdata_sec); + listbuffer[0x0c+(listentry_pos<<1)]=curdata_trk; + listbuffer[0x0d+(listentry_pos<<1)]=curdata_sec; + seek_sect(curdata_trk,curdata_sec); + if (preproc(procmode)) break; + } + else { + /* Check for all-zero sectors for sparse T file */ + for (i=0;i<256;i++) databuffer[i]=0; + i=0; + while((c=fgetc(from_file))!=EOF && i<256) databuffer[i++]=c; + while(i && !databuffer[i-1]) i--; + if (!i) { + listbuffer[0x0c+(listentry_pos<<1)]=0; + listbuffer[0x0d+(listentry_pos<<1)]=0; + } + else { + new_sector(&curdata_trk,&curdata_sec); + listbuffer[0x0c+(listentry_pos<<1)]=curdata_trk; + listbuffer[0x0d+(listentry_pos<<1)]=curdata_sec; + write_sect(curdata_trk,curdata_sec,databuffer); + } + if (c == EOF) break; + ungetc(c,from_file); + } + if (++listentry_pos >= 0x7a) { + new_sector(&newlist_trk,&newlist_sec); + listbuffer[1]=newlist_trk; + listbuffer[2]=newlist_sec; + write_sect(curlist_trk,curlist_sec,listbuffer); + curlist_trk=newlist_trk; + curlist_sec=newlist_sec; + for (i=0;i<256;i++) listbuffer[i]=0; + listentry_pos=0; + listbuffer[5]=(++list_no*0x7a) & 0xff; + listbuffer[6]=(list_no*0x7a) >> 8; + } + } + + listbuffer[1]=listbuffer[2]=0; + write_sect(curlist_trk,curlist_sec,listbuffer); + write_sect(0x11, 0, vtocbuffer); + dir_entry_data[33]=new_sectors & 0xff; + dir_entry_data[34]=new_sectors >> 8; + fseek(image_fp,dir_entry_pos,SEEK_SET); + /* writing ff first ensures directory is always in a safe state */ + fputc(0xff,image_fp); + for (i=1;i<35;i++) fputc(dir_entry_data[i],image_fp); + fseek(image_fp,dir_entry_pos,SEEK_SET); + fputc(dir_entry_data[0],image_fp); + + fclose(from_file); + } + +int main (int argc, char *argv[]) { + char *image_name, *image_mode, *a2_name, *basename, *typestr; + unsigned int i, bad_vtoc; + char *ls_cmd, *in_cmd, *out_cmd, *rm_cmd; + char *ls_hlp, *in_hlp, *out_hlp, *rm_hlp, *general_hlp; + int dos, x, image_rw=0; + void (*command)(void) = NULL; + +#ifdef DOS + dos=1; + ls_cmd="dir"; + in_cmd="in"; + out_cmd="out"; + rm_cmd="del"; + ls_hlp=in_hlp=out_hlp=rm_hlp=general_hlp=(char *) DOS_HelpText; +#else + dos=0; + general_hlp="Invoke as a2ls, a2in, a2out, or a2rm.\n"; + ls_cmd="a2ls"; + ls_hlp="Usage: a2ls \n"; + in_cmd="a2in"; + in_hlp= + "Usage: a2in [-r] [.] []\n"; + out_cmd="a2out"; + out_hlp="Usage: a2out [-r] []\n"; + rm_cmd="a2rm"; + rm_hlp="Usage: a2rm \n"; +#endif + + baseaddress=0x2000; /* default, hi-res page 1 */ + rawmode = begun = 0; + extfilename = a2_name = image_name = ""; + +#ifdef DOS + basename=""; + if (argc >=2) basename=argv[1]; +#else + basename=argv[0]; + /* strip off any leading directories */ + basename+=(i=strlen(basename)); + while(i-->0 && *--basename!='/'); + if (*basename=='/') basename++; +#endif + + if (!strcmp(basename,ls_cmd)) { + if (argc !=2+dos) quit(18,ls_hlp); + else { + image_name=argv[1+dos]; + image_rw=0; + command= a2ls; + } + } + else if (!strcmp(basename,out_cmd)) { + if (argc > 1+dos && !strcmp(argv[1+dos],"-r")) rawmode=1; + x=3+dos+rawmode; + if (argc != x && argc != x+1) quit(19,out_hlp); + else { + image_name=argv[x-2]; + image_rw=0; + a2_name=argv[x-1]; + if (argc-x) + extfilename=argv[x]; + else + to_file=stdout; + command= a2out; + } + } + else if (!strcmp(basename,in_cmd)) { + if (argc > 1+dos && !strcmp(argv[1+dos],"-r")) rawmode=1; + x=4+dos+rawmode; + if (argc != x && argc != x+1) quit(20,in_hlp); + else { + typestr=argv[x-3]; + image_name=argv[x-2]; + image_rw=1; + a2_name=argv[x-1]; + if (argc-x) + extfilename=argv[x]; + else + from_file=stdin; + switch(typestr[0]|0x20) { + case 't': filetype=FILETYPE_T; break; + case 'i': filetype=FILETYPE_I; break; + case 'a': filetype=FILETYPE_A; break; + case 'b': filetype=FILETYPE_B; break; + case 's': filetype=FILETYPE_S; break; + case 'r': filetype=FILETYPE_R; break; + case 'x': filetype=FILETYPE_X; break; + case 'y': filetype=FILETYPE_Y; break; + default: quit(21,": one of t,i,a,b,s,r,x,y without -\n"); + } + if (typestr[1]=='.') { + if (filetype==FILETYPE_B) + sscanf(&typestr[2],"%x",&baseaddress); + else quit(22,"Base address applicable to type B only.\n"); + } + else if (typestr[1]!=0) + quit(23,"The only modifier for is .\n"); + command= a2in; + } + } + else if (!strcmp(basename,rm_cmd)) { + if (argc != 3+dos) quit(24,rm_hlp); + else { + image_name=argv[1+dos]; + image_rw=1; + a2_name=argv[2+dos]; + command= a2rm; + } + } + else + quit(25,general_hlp); + + if (image_rw==1) image_mode="rb+"; else image_mode="rb"; + if (!(image_fp=fopen(image_name, image_mode)) || seek_sect(0, 0)) { + perror(image_name); + quit(26,""); + } + + /* prepare source filename by padding blanks */ + i=0; + while(i<30 && a2_name[i]) { padded_name[i]=a2_name[i] & 0x7f; i++; } // Compiler cleanup + while(i<30) padded_name[i++]=' '; + + /* get VTOC and check validity */ + read_sect(0x11, 0, vtocbuffer); + bad_vtoc=0; + for (i=0; i@JVQNPm~^ZPe_+9S{C5bh>DUi{kYu{Wz!v{s=h>1_ zdLmMKJ|gLa-iXj0kvk&7XAwy+oQgLl00|^3q|H8|6Z*Em zt|0PKCFNt0z!wo#i3CnZif#SG)b8%~Q<0L>w8Zw$BI>8SWjV`4Lk4>~Z_noC289;J z2wFt`Rw?KcPDXejFUxCDzvG!3^wt}?BFq*YufNFXzKbvshS8^7DcXCrB8k=>LlIjg9Ypzvh(Rq7i58b^CIJ$)0Xue zWS!46jHZ8O6Iz-w)swu)7Hf||V%v8Ght;pUV_U66{Ysn@-;~wk5>vb~vw^W4v1&`M73TnO?x<-7r$Sb*`gXdGqtnv_`|ApIUe?AhzGt- z_vRiM`!U*`8C#FYTz3oO7+GvPUadyr$v#noKjy7S=U3hA9=(6LQJV>QGv(z*_sHyH zqqRFi{R;YemK!~$XD+rcH#TQ_^#07&q>!#Uo9(HuPus>a+x#Qb*)#R^gXwl>rn(1K z=}^EZ!)VjZB)X!p@@AfhqA#sY{h@QRs_&cvT~XC|U6y?~J7n;U^t0ra%#52ZZNI+e zjX!%glvh^08IXfDo5OX=mPq}!?G4c#JKx^l{?5Vo-aqo;M@K*Y^&8`c|5 zW^to$Q-!~urCK5h*2JXbP;E-8Ev^56t=C*T@VfNt2Q}{6y{D;p?^`XcZ8z+@aqtlJ zz`HjcI?N9JAY<6@5t$?H9iRQ>^Djn?zPam`F}IG*y6txD%pG^$b@x5lz4wm$oAG}; zVWQ5OX0@F&+AO=n7H?RuM8 zpP)D0Vq+|~GA6w}U7s~f&)#lK(_f>vB=l!f#tzGZZ_;(6CypGJbO3xTIZn%9!#)$ZG`0(3D+&SXX(tf*r)X-73jSlc=?KB@X@D=Bv+%3CSk+*d zINSik1T0>Mg+G^VYVhaN#YDQub>urHI;WZ@#0Lgf0$~p|z<6*u&q>%yzcdzHN(KeH zy1Tm*NOyN^aDd-@vA?TKe6{%X__D05g1siu zSnFgT++kPKDyGPkwukC2>HEVX5!g`G`{XMwD1%F&awBpu%FqGU#Q>}$WuJ&G|dQ59`NjY}T zxkI~`tJwiHb~^oI#gsCqOS3eO)r=CWekPh~oz?YQcQ%hv*VsKbvPZXCLZx;evnrF_ zy%lPZK0I4Y2CCvlo*li_qe-?U)jC za-)AVY@62g8f}Jk%Z;2^ADd&Vc_$TH_|#pH-evudNqAa4cdkU-6T~?%BId8_+YW9p zYr#^Q0d11(ZU=Ou2Y0Z^J0(kKxRfOyNcPMe9xI)!eIM_K2q2EALLQi#0^iOQHc}|I`D<{SZTUWia*mePu{L9Yx7iPa= zC=^N`<{zV7E7_VIe#Z%&+tF$YrDgLp!UVhY+z7RZr%UvYX-!pQfh9EXWHw(hroMV- z*2hvG6u)<(t<9gWTKx{#@v*&*y^eIg@2@_8eW?XkVe;=A;R_c6Ob3?_(>xxJ8;vs(m#i#1kN4)udjJWq8pZxR|roS?{=ko zLt1%8`K{&mm-FRI%BTDLSG>MSt@yIyao-Z(Qr`*RAb+zz)qm9Q^R4l%@GbV=?i=s3 z`^NZY`2NA~^=EB*c$2W{pM2j}d|$EP1EypAp|1|z-F2+u^Us+ML&tv%HT%u}r)?{} zrYr|e8~IV9vc9p=`!{%115G(|gK*YR;1|9&$VD53 zuMCn|HOY??%`7}hxD^|DZl@P+2Dl#xr$ppbZy?3X%ezTn7vZ`4tGm0oc^9|^ecaqW zx?Iq=ppQMULB5}8*E;2gNtxZ1W#BU5M#x(+T;j{@v^oa%50#PuTElKDXSZz-9wwy^ z5-wc6D4U^qi-?s()4a~8%}a~mY0ySvTS%LgM+7`MDU2)nbi z?$nkw-=U54=}U{q{>?zh)^tt*GJHFxW3?TpU|MW~;_u_+?j2v|i3 z94hW;h0N$_BC8|_j2?FIAdzxZvt(2C5<6x-(Nbx{o6DhL&?<<9T)}zd4QOoOAp-l% z<`><~NCMYfF7}l?N?J-DCq0i6A7hEe3RZQrEo{ZcQ7_F~S>0mQ^e&4>vukYq%4+q! zOFK6}+hm;{>TZUE&b?O7HC3iON&=4(XqqQU(%+jPX(lNZZeSbDs($4i5=%oKV_y?3 zP_#D0>M_BgW5k8rJdu56qn5mG8EI)8?>P%U)bH$SDikHzXr3f-h(&!{eucD(+5mYO ztknBxWFw8#+a^LG;&@41x0Jw~#tX}cltg1jvh^E7H&v_Gb)YVNRv+C7P@ zRg0vDx&H3J$~LuE+Y+5BWlc$jk`_Rxc#_ba`{XBy)mrU$s0sf3BeNw>iQjQ#uH;En z{|LVykUVIM1k{Iv@lZinZcY~Gxo>EP}3 z05;PsJ*`%cEPhPPnvZxfvoWC z1P+XWYpHbS`t#j6?4&AodKEjU3XX`dUE!)LV_i)fK_AJCW518>qoxWfIP zz38_D#&wPLzh^UW`zj?p>?PY@bL{DAf9RMC_T+a}JPpOeGaeej9c!!hPdoNDjd;7F z4I+fyiWBzj;+m>Tb}1!$6bOKe;q3~r#hx_DyA@#%MWJy`3YwdZzN}3Kt7?hl=xFs8cK*RO>WP zh=1DY$B4&K-E^NPN1L$n?Nx21dz6wUg|k-3Rxi{+PV~|WFtmnxVV43UJycVFshW=w z2(OlT0x>*&JhrcLKh$avoW!M%lc}J(!4K2eGU9!OPGj8f{5-9#fsU;MDxhc5O3n59 zr@Hs~?{n{8G{?&hyc`VM3*K|z;r@Vo_kDIjN^I*;Dx2w#4c_$BgiRexpmg)eDvueu zBzLDDdI>#zW^DjWEzc5fRDm7Cqpa=p2_7%yK=05@@>8^rUW747PWD1uq(s``*KCr^ zu$Ff!5W&Z$YwcEO`W7M%Vb_ShglL3#mlBxlrAE5n0~HbrQ#y>hIvCp^VT8ccx}WLL zQiK(abZr)XPuDzDO)ext9g$}cK_Sr9p;N0VKUVwXfw|IOpqtR}>5`dFYH(7f!l@t`_QN#RE}5WatsNfysFz@V zg2_lrXoJBkVFgT~Fh@J-(MYNMyDlxc@{W#=wSKO2-hU+PTNm6GeD9+(O}HE`Ht3mW zP&dYp{pBvYN8x3KxO3$?;?Ch&^P8T5@C3Eh1P6Wo7Vb}5;8wRAW=lvWC8|~!O3YFU z3@yn}54LkB-LcXCK~{>7Vf9r(2-8=^`vbHEeoBUrVbOzLxHO7RB&75S5`A8BCai#Y z7N&$Qm+dqU$57a*$Sxu@D)K_w17&zh2R*hQ?XmtGp^*4bG1KUjX96XpSxu292(IF8A>OWO+FI3SXWiX5;aBq|2&iCiK9qK7@aBa?!WkmhF z*me#^ZeC`*L7i8%iX&=sv;tIgrzYC}r_k>(uL0y@pPny!tX2B(B| z)JvL~o*`-_pAAL0b7Y+t@E#yAZpMZ;aY(j5=fs$@9H&3`1k+NML)u(USgpRY*|NGU zryXX*>xe7+L?(ngSI1Jib6xHn?pT#mqWR!UbrW6grS2sz_Y3alc$a&c`)!w-bGPyS zd-of>T7O{<@n;LOiLCd!vt@(VeXswX{U#bQi}>#rW)j)xb>A(UyzYDWg6Rc^xWe3~ znYnYCi)Ob^a^@Da=Q}vZtY)ro(%ZAA)8!#1BfXmI}nu{RR!8(eH3g4yebFedt3THVc&2lt3rsuPTliB>-S-WT> zV%a7a&Ys>hr;wXH&B0D9m^m$X)})q#v4!#c`2{oYV<*q%_QjF|-+hjzne(R4%AFgJ zpI*r3&7M5jQ8e?)?qf-3&6{zhIN1M`qTFfhtinQ;%PpGHOskt;Py}^iClyYcmOH&k zU<}t^Km3jf+(S<;UcPcI**<11!)QO;@Pondb+TPZW|-%VOrnmx2pDFdh<#M1rFq}J zcf?=zF|33_a+qDJy07`*J9`gxMYe~x*D;MRhKIgs3Oo>aE-+eNBliTp3EUe`R?h7&MDF3bwZC4?Wz;LR7#I1QlHSF2%jnP zU&6wNN;)^cMq-HffYQ}5M(u?;2i}Z)tH_Ot(5uM16f1m4>3Ky;6E48iI=F_tvxeQX zS<;U=tY|~o^N=~6O$%kWf1toM^ASbvQK0_vmkKlmYDh)wZ_4MCteb(uohR>5+>@ZT z?2Vh_vG7&~9{*6vPM|zSDW48={}`rOdgGBj5cw5Eo`Fb~3A5D!dQAca!?scjKb@?v zR%BdddEDy(c1tLfSexf$AF5?vt#$F-b2Od2M`1q*y}O?D;}b&-ENrxEtgj)5BHS zKZa@6*irFz*1=QWy>$(5)s?)fK)iR!iC~J#3&ujay1K-{&^Czdf;ov6pS9Uj71{u`lmrNE_l8vqoAiTpEmVvb z^%CQR8=#7?r~kJVVVKq&Ct$*JJ;OM;DM4342yztLKH^zR4a|tm3cS)h05jwm6=u6w zSp5M7Ue?ioSgVcf+)(^Q-mWn8&XZv{?@on%*>DzZ4|k~-d`TT8+BKq~UJQHBhG`8u z^3_v5r`iROK4!IddmW@=9U&<#poNQz;a#TCP*)PIYk^mYa2Y!{6o}RpXPMMfYqd^x zcZ8i9frj}Q&Fs^wdY>`+7WC(63-o9Hmcz;t9nXGI1KEl~(oQ%xpeOP2VI>QK@4FQI z(&gY*g}#Gqqpu@_vE$2I=vj4N4fF+jC?R-23B0RtN)0?1&eJS}b_w`J2OXoPrw>Xu zi~6!WXEBTku!7Sc1_99|e?ocWPhsgIu4)M?Dd|cNDkac=ibC*YI!`#Nq%ZzZ5k66% zNa15;@kfgAsRFuCaUE9_3cRhz`;-!mzLgEWrv%=IOC}wZq7UpL5E^JA@QyclK@k~9 zYymlY$P$Q#gAHNT8f>Ujp>9A{x+Yw*77hmN6pD6)f@{J7_^pRLaxk`*3;mg>w3+Vtpp58V(G+Y)`#%2=1)q*jnMe807m3d$b19 z!mtWO!N|(mY66|$S^}qI{^o!;+)|b&ysyNM7i5BXIAT&`ywQBHTPcky!IMhq4kdU> z37l3+cPb@~N|&l@*>^%w(@u3MY7)GFW_r5me+Phsr<9V@3g6QSO``*k0R|pEuty0t zDJ%0mW#O~O zlxM$Cp6!IEFdxxdxl_twD4;VowVqZMLm6K{8H=IEz`=v_ECbHiA#i&$NHVGeC6n48 zo|vX^r+0QsR@Dr5H0d5)wgu*RxJz)t3ko}ZL&2w|GE7hWf~l`hXMOTe>#p4g-`%xa zY~Fu(-#hP#Zy#)JGNz>(=#}RG@cG^4_%yiw8fLqE6&4Te>w|04U+_nB|B`%vo#%4h zaQ*WI61_U+qTb9bBanA3vxa&7avA!|8$Y?`^}4j5jKl~OKmim$0Te(16hHwKKmim$ z0Te(16hHwKKmim$0Te(16hHwKKmim$0Te(16hHwKKmim$0Te(16hHwKKmim$0Te(1 z6hHwKKmim$0Te(16hHwKKmim$0Te(16hHwKKmim$0Te(16hHwKKmim$0Te(16hHwK zKmim$0Te(16hHwKKmim$0Te(16hHwKKmim$0Te(16hHwKKmim$0Te(16hHwKKmim$ z0Te(16hHwKKmim$0Te(16hHwKKmim$0Te(16hHwKKmim$0Te(16hHwKKmim$0Te(1 z6hHwKKmim$0Te(16hHwKKmim$0Te(16hHwKKmim$0Te(16hHwKKmim$0Te(16hHwK zKmim$0Te(16hHwKKmim$0Te(16hHwKKmim$0Te(16hHwKKmim$0Te(16hHwKKmim$ z0Te(16hHwKKmim$0Te(16hMKW7BHrz8W`r{PbY}S{O)ps0Xl{mW@BJ^<NBM2fAvlHUo{{NPXDX01BW03ZMWA zpa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S> z01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW0 z3ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWA zpa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S> z01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW0 z3ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWApa2S>01BW03ZMWA cpa2S>01BW03ZMWApa2S>01BYMuU+8Z0f>$6UjP6A literal 0 HcmV?d00001 diff --git a/bin/src2dsk.sh b/bin/src2dsk.sh new file mode 100755 index 0000000..6d21c0a --- /dev/null +++ b/bin/src2dsk.sh @@ -0,0 +1,152 @@ +#!/bin/bash +# Version 5 +# +# Purpose: Assemble, Link, & Copy a binary to a DOS 3.3 .DSK image without all the cc65 library crap. +# Usage: src2dsk.sh {sourcefile} +# +# Example: +# 1. src2dsk.sh barebones.s +# +# foo.s <- input assembly source file +# foo.o <- output of assembler +# foo.bin <- output of linker +# foo.dsk <- DOS 3.3 disk contaning binary 'FOO' +# +# 2. Mount 'barebones.dsk' in your emulator +# +# If you try BRUN'ing the file the RTS won't exit to DOS 3.3 / BASIC properly. +# A simple work-around is to BLOAD, then run it. +# 3. BLOAD BAREBONES +# 4. CALL -151 +# 5. AA72.AA73 +# 6 Use whatever addres is displayed (bytes are swapped): +# 1000G +# +# The 'barebones.s' exits via 'JMP $3D0' to warmstart DOS. +# +# You can get a blank DSK here +# * ftp://ftp.apple.asimov.net/pub/apple_II/images/masters/ + +## wget ftp://ftp.apple.asimov.net/pub/apple_II/images/masters/emptyDSK_Dos33.zip +# curl -# -o EmptyDSK_DOS33.zip ftp://ftp.apple.asimov.net/pub/apple_II/images/masters/emptyDSK_Dos33.zip +# +# I've included an 'empty.dsk' in the repo. for convenience +COPY=cp +DEL=rm + +# Verify we have a .s file ! + if [[ -z ${1} ]]; then + echo "ERROR: need an assembly source file (e.g. foo.s) to build from!" + exit 1 + fi + +# Verify we can find toolchain +# http://www.cc65.org/doc/ca65-2.html#ss2.2 + if [[ -z ${CC65_HOME} ]]; then + echo "INFO: 'CC65_HOME' not set, should point to directory containing 'ca65', 'ld65'" + CC65_HOME=../bin + echo "INFO: Trying '${CC65_HOME}' for assembler and linker" + fi + +# Assembler + if [ ! -f ${CC65_HOME}/bin/ca65 ]; then + echo "ERROR: Couldn't find assembler 'ca65' !" + exit 1 + fi + +# Linker + if [ ! -f ${CC65_HOME}/bin/ld65 ]; then + echo "ERROR: Couldn't find linker 'ld65' !" + exit 1 + fi + +# Verify we can find a2tools + if [ ! -f a2in ]; then + echo "WARNING: Missing a2tools 'a2in', attempting to build" + echo "INFO: Compiling 'a2tools' ..." + echo " gcc -DUNIX a2tools.c -o a2in" + gcc -DUNIX a2tools.c -o a2in + ${COPY} a2in a2rm + ${COPY} a2in a2ls + if [[ -f a2in ]]; then + echo "... success!" + else + echo "ERROR: a2tools missing: 'a2in'" + echo " " + echo "The original tools can be found here:" + echo " * ftp://ftp.apple.asimov.net/pub/apple_II/utility/" + echo " * http://slackbuilds.org/repository/14.1/system/a2tools/" + echo "To download:" + echo " curl -o a2tools.zip ftp://ftp.apple.asimov.net/pub/apple_II/utility/a2tools.zip" + echo "This repo. contains a copy but was unable to compile it." + exit 1 + fi + fi + +# Filenames and extensions + #http://stackoverflow.com/questions/965053/extract-filename-and-extension-in-bash + # Get filename without path + # Get filename without extension + DIR=$(dirname "${1}") + FILENAME=$(basename "${1}") + FILE="${FILENAME%%.*}" + + DEBUG= + #DEBUG=echo + #${DEBUG} "... dir : ${DIR}" + #${DEBUG} "... name: ${FILENAME}" + #${DEBUG} "... file: ${FILE}" + + SRC=${FILE}.s + OBJ=${FILE}.o + BIN=${FILE}.bin + DSK=${FILE}.dsk + + ASM_FLAGS="--cpu 65c02" + LNK_FLAGS="-C apple2bin.cfg" + CnL_FLAGS="-t apple2enh -C apple2enh-asm.cfg -u __EXEHDR__" + +# Assemble & Link + ${DEBUG} ${DEL} ${BIN} ${OBJ} + ${DEBUG} ${CC65_HOME}/bin/ca65 ${ASM_FLAGS} -o ${OBJ} ${DIR}/${SRC} + ${DEBUG} ${CC65_HOME}/bin/ld65 ${LNK_FLAGS} -o ${BIN} ${OBJ} + + # Default Linker Config script can't target address < $803 + #${DEBUG} ${CC65_HOME}/bin/cl65 ${CnL_FLAGS} -o ${BIN} ${SRC} + +if [ -f ${OBJ} ]; then +# Copy to bootable empty DOS 3.3 .DSK + # We need to uppercase the file name for a DOS 3.3 DSK + # The ${1,,} is a Bash 4.0 uppercase extension so we can't use that + # Likewise, GNU sed 's/.*/\L&/g' doesn't work on OSX (BSD) + A2FILE=`echo "${FILE}" | awk '{print toupper($0)}'` + + if [ ! -f ${DSK} ]; then + echo "INFO: Using blank disk: ${DSK}" + ${COPY} emptydos33.dsk ${DSK} + else + echo "INFO: Updatig existing disk: ${DSK}" + # If you want to keep an existing disk then you'll + # will want to first remove the old file on the .DSK image + ${DEBUG} a2rm ${FILE}.dsk ${A2FILE} + fi + + if [ -f ${BIN} ]; then + ${DEBUG} a2in -r b ${DSK} ${A2FILE} ${BIN} + + # Debug + #${CC65_HOME}/bin/od65 --dump-all ${OBJ} + + # Done! + if [ -f ${DSK} ]; then + echo "INFO: Created: ${DSK}" + else + echo "ERROR: Couldn't create: ${DSK}" + fi + else + echo "ERROR: Failed to link" + fi +else + echo "ERROR: Failed to assemble" +fi +