diff options
| -rw-r--r-- | ksiders/Makefile | 67 | ||||
| -rw-r--r-- | ksiders/README.txt | 77 | ||||
| -rw-r--r-- | ksiders/atdos.h | 137 | ||||
| -rw-r--r-- | ksiders/atr.c | 1422 | ||||
| -rw-r--r-- | ksiders/atr.h | 65 | ||||
| -rw-r--r-- | ksiders/atr.txt | 521 | ||||
| -rw-r--r-- | ksiders/atrdir.1 | 65 | ||||
| -rw-r--r-- | ksiders/atrdir.c | 89 | ||||
| -rw-r--r-- | ksiders/atrextr.1 | 64 | ||||
| -rw-r--r-- | ksiders/atrextr.c | 63 | ||||
| -rw-r--r-- | ksiders/atrsrc.zip | bin | 0 -> 18785 bytes | |||
| -rw-r--r-- | ksiders/kboot.h | 61 | ||||
| -rw-r--r-- | ksiders/makeatr.1 | 92 | ||||
| -rw-r--r-- | ksiders/makeatr.c | 41 | ||||
| -rw-r--r-- | ksiders/sortatr.1 | 80 | ||||
| -rw-r--r-- | ksiders/sortatr.c | 39 | ||||
| -rw-r--r-- | ksiders/unmakatr.c | 43 | 
17 files changed, 2926 insertions, 0 deletions
diff --git a/ksiders/Makefile b/ksiders/Makefile new file mode 100644 index 0000000..674b3e6 --- /dev/null +++ b/ksiders/Makefile @@ -0,0 +1,67 @@ + +# This Makefile has been tested with GNU make and /usr/ccs/bin/make +# on a Solaris 2.6 (SunOS 5.6) system. + +CC=gcc +COPT=-O2 +CFLAGS=-Wall $(COPT) -ansi -fpack-struct + +# -pedantic complains about some perfectly harmless signed/unsigned +# char pointer stuff. + +# Note: -fpack-struct works on gcc's at least as old as 2.95.3 +# If you're not using gcc, find your compiler's equivalent option +# (/Zp on Microsoft compilers). + +DESTDIR= +PREFIX=/usr/local +BINDIR=$(PREFIX)/bin +MANDIR=$(PREFIX)/man +MAN1DIR=$(MANDIR)/man1 + +# some systems need this instead: +#MANDIR=$(PREFIX)/share/man + +# Comment out next line if your system does not support gzip'ed man pages +GZIP_MAN=y + +EXES=atrdir atrextr makeatr sortatr unmakatr +MANS=atrdir atrextr makeatr sortatr + +all: $(EXES) + +clean: +	rm -f $(EXES) atr.o tags *~ *.bak + +install: all +	mkdir -p $(DESTDIR)$(BINDIR) $(DESTDIR)$(MANDIR) ;\ +	for exe in $(EXES) ; do \ +		strip $$exe ;\ +		cp $$exe $(DESTDIR)$(BINDIR)/$$exe ;\ +	done ;\ +	for man in $(MANS) ; do \ +		if [ "$(GZIP_MAN)" = "y" ]; then \ +			gzip -c < $$man.1 > $(DESTDIR)$(MAN1DIR)/$$man.1.gz ;\ +		else \ +			cp $$man.1 $(DESTDIR)$(MAN1DIR) ; \ +		fi ;\ +	done +	if [ "$(GZIP_MAN)" = "y" ]; then \ +		cd $(DESTDIR)$(MAN1DIR) && rm -f unmakatr.1.gz && ln -s makeatr.1.gz unmakatr.1.gz ;\ +	else \ +		cd $(DESTDIR)$(MAN1DIR) && rm -f unmakatr.1 && ln -s makeatr.1 unmakatr.1 ;\ +	fi + + +atr.o: atr.c atr.h atdos.h kboot.h + +atrdir: atrdir.c atr.o + +atrextr: atrextr.c atr.o + +makeatr: makeatr.c atr.o + +sortatr: sortatr.c atr.o + +unmakatr: unmakatr.c atr.o + diff --git a/ksiders/README.txt b/ksiders/README.txt new file mode 100644 index 0000000..b6c5934 --- /dev/null +++ b/ksiders/README.txt @@ -0,0 +1,77 @@ + +This is a quick & dirty Linux/UNIX port of Ken Siders' old Atr Utils +package for MS-DOS. + +The original MS-DOS sources can be found in the file atrsrc.zip, or +you can download them from Ken's page: +	http://atari.ksiders.tzo.com/a8emulators.html + +Please do NOT contact Ken Siders about bugs or issues with these ported +and modified versions of his utilities. They are provided as-is, by me, +B. Watson (urchlay at urchlay dot com). + +The utilities are: + +atrdir   - Get a directory of an ATR image +atrextr  - Extract files from an ATR image to the current directory +makeatr  - Make a bootable "K-file" disk from an Atari executable +sortatr  - Sort the directory of an ATR image in alphabetical order +unmakatr - Reverse of makeatr: extracts the Atari exe from a K-file disk + +All utilities work only with AtariDOS 2.x or MyDOS compatible images. +SpartaDOS, AtariDOS 3/4, DOS XE, and other non-MyDOS-compatible formats +are not supported. Atari DOS 2.5 images are only partially supported. + +All utilities have been tested on Linux (with gcc-3.4.4) and Solaris 2.6 +(with gcc-2.95.3). They produce identical output on both platforms. +However, Solaris 2.6 doesn't support gzipped man pages, so you have +to install with "make install GZIP_MAN=n". + +I've written rudimentary man pages for the utilities. Any errors in the +man pages are my own fault. + +I've made a few changes to the library (atr.c). Some are bugfixes, some +are feature enhancements, and a few are just to make the utilities behave +more like UNIX utilities are expected to behave. + +- AtariDirectory() (used by atrdir) now partly supports DOS 2.5 extended +files (using sectors > 720). They are listed (with "<"), but their size +is not (shows up as "??"). (The original DOS version was "blind" to +files like these, like DOS 2.0S is). + +- AtariDirectory(): Also, MyDOS directories are now listed (with ":"), +though their size is listed as "??". + +- AtariDirectory(): Stop listing files after the first unused entry, +as Atari DOSes do. For normal disks, this really wasn't a problem, but +e.g. the HomeSoft games disks store file data in the higher-numbered +(unused) directory sectors, cause atrdir to print garbage to the terminal. + +- PatternMatch() (used by atrdir and atrextr) now always matches all +files, if the wildcard pattern is "*" or "*.*". Also, wildcard patterns +are now case-insensitive. + +- SortAtariDir() (used by sortatr) now correctly fills unused characters +in the filename with spaces, as Atari DOSes do. Previously, they were +filled with nulls (Atari heart character). + +- ExtractAtariFile() (used by atrextr) no longer includes a trailing +dot in the extracted filename, if the file in the image has no 3-character +extender. + +- ExtractAtariFile(): extract path now may be up to 4096 bytes, and +UNIX-style / is used for delimiter instead of DOS \ + +- atrextr: file argument is now optional (defaults to *.* if missing +or blank). + +- atrextr: added optional dir argument. Files will be extracted to this +directory (which will be created if necessary). + +- all utilities: exit status is now 0 for success, non-zero for any error. + +- atr.c (all utilities): Added support for detecting endianness and +swapping bytes in start sector and sector count, if needed. Atari and +PC are both little-endian platforms, so the DOS sources didn't need to +support big-endian platforms. Tested on Solaris 2.6 on Sparc hardware +(big-endian). diff --git a/ksiders/atdos.h b/ksiders/atdos.h new file mode 100644 index 0000000..34849b6 --- /dev/null +++ b/ksiders/atdos.h @@ -0,0 +1,137 @@ +/* Copyright 1997 Ken Siders */ + +/* dos compatability types */ +#define DOS_ATARI 1 +#define DOS_MYDOS 2 +#define DOS_SPARTADOS 3 +#define DOS_LJK 4 + +#define MAX_ATARI_FILES 64 + +/* disk format types */ +#define FORMAT_SD 1 +#define FORMAT_ED 2 +#define FORMAT_DD 3 +#define FORMAT_SD_CUSTOM 4 +#define FORMAT_DD_CUSTOM 5 +#define FORMAT_DEFAULT 6 + +/* open modes */ +#define ATARI_OPEN_READ 4 +#define ATARI_OPEN_WRITE 8 +#define ATARI_OPEN_DIR 6 + +/* these will be in variables later */ +#define firstDirSector 361 +#define lastDirSector 368 +#define vtocSector 360 +#define vtocSector2 0 +#define dirEntrySize 16 +#define dirEntriesPerSector 8 + +#define DELETED_FLAG    0x80 +#define INUSE_FLAG      0x40 +#define LOCKED_FLAG     0x20 +#define MYDOSDIR_FLAG   0x10 +#define OPENOUTPUT_FLAG 0x01 +#define DOS25EXT_FLAGS  0x03 + +struct S_AtariDosDirEntry +   { +   char flag; +   unsigned short sectorCount; +   unsigned short startSector; +   char fileName[8]; +   char extender[3]; +   }; + +typedef struct S_AtariDosDirEntry AtariDosDirEntry; +typedef AtariDosDirEntry *AtariDosDirEntryPtr; + +/* 20070518 bkw: +	Nothing actually uses this struct, and it's got endianness +	issues... */ +#if 0 +struct S_AtariDosLink +   { +   int fileNo:6; +   int nextSector:10; +   int shortSector:1; +   int bytesInSector:7; + +   }; + +typedef struct S_AtariDosLink AtariDosLink; +typedef AtariDosLink *AtariDosLinkPtr; +#endif + +struct S_AtariVtoc +   { +   byte reserved[10]; +   byte vtoc[118]; +   }; + + + + +struct S_AtariFile +   { +   AtrFilePtr atr; +   unsigned short startSector; +   unsigned short currentSector; +   unsigned short sectorSize; +   unsigned short numberOfSectors;  /* no. of sectors in file */ +   unsigned long fileSize ; /* not used yet */ +   byte openFlag; +   byte eofFlag; +   short currentOffset; +   short bytesData; +   short sectorLinkOffset; +   short fileNo; +   unsigned char sectorBuffer[256]; + +   }; + +typedef struct S_AtariFile AtariFile; +typedef AtariFile * AtariFilePtr; + + + + +struct S_AtariFileInfo +   { +   unsigned long fileSize; /* not implemented */ +   unsigned short startSector; +   unsigned short sectorCount; +   char fileName[13]; +   int locked; +   int attrib;        /* internal */ +   int dirSector;     /* internal */ +   int dirEntry;      /* internal */ +   char *pattern;     /* internal */ +   char *atrName;     /* internal */ +   int dosType; +   short fileNo; +   int flag;    /* from dos */ +   }; + +typedef struct S_AtariFileInfo AtariFileInfo; +typedef AtariFileInfo *AtariFileInfoPtr; + + + +/* function prototypes */ + +void MakeFileName( char *result, char *fileName, char *extender ); +int PatternMatch( char *pattern, char *fileName, char *extender); +int AtariFindFirst( char *atrName, unsigned attrib, +    char *pattern, AtariFileInfoPtr fileInfo ); +int AtariFindNext( AtariFileInfoPtr fileInfo ); +AtariFilePtr OpenAtariFile( char *atrName, char *fileName, byte mode); +int AtariDirectory( char *atrName, char *pattern); +long ReadAtariFile( AtariFilePtr atFile, char *buffer, long bytes ); +int CloseAtariFile( AtariFilePtr atFile ); +int EofAtariFile( AtariFilePtr atFile ); +long AtariFileSize( char *atrFile, char *fileName ); +int FixAtariFileNo( char *atrName, char *fileName, int fileNo ); + diff --git a/ksiders/atr.c b/ksiders/atr.c new file mode 100644 index 0000000..2c3942f --- /dev/null +++ b/ksiders/atr.c @@ -0,0 +1,1422 @@ +/********************************************************************* +   ATR/XFD File handling library +   (C) Copyright 1997 Ken Siders     + +   This file can be used in any freeware or public domain software +   as long as credit is given. + + +History + +00.000  6/16/97    Initial version +00.001  6/24/97    Fixed AtariFileSize, Added EofAtariFile and +                   ExtractAtariFile functions +00.002  6/26/97    Added SortDirectory Function +00.003  7/14/97    Fixed Double density to treat first 3 sectors as   +                   Single Density. +00.004  7/16/97    Added CreateBootAtr +00.005  8/22/97    Added ExtractExeFromBootAtr +00.006  9/04/97    Fix signature check + +********************************************************************* + +To do: + +1 Clean up warnings + make more portable +2 Allow opening write-protected ATRs +3 Allow more than one reference to an ATR file to be opened so more  +   than one atari file can be opened at once. (Keep a count) +4 More specific error returns +5 Implement XFD handling +6 Create documentation +7 Optimize if necessary +8 Implement DCM images (maybe) + + +*********************************************************************/ + +#define wide 1 + + +/* compile with /Zp option */ +/* 20070518 bkw: or -fpack-struct on gcc */ + + +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> +#include <stdlib.h> +#include <ctype.h> +#include "atr.h" +#include "atdos.h" +#include "kboot.h" + +AtrHeader hdr; + +int lastAtariError = 0; + +static unsigned char sectorBuffer[256]; +static int CompareName( const void *a, const void *b ); +static int verbose = 0; + +/* 20070518 bkw: min() isn't standard on Linux. If you're porting to +	some other UNIX and get errors about min() already being defined, +	just comment this out. */ +static int min(int a, int b) { +	return ((a < b) ? a : b); +} + +/* 20070518 bkw: As written, the DOS sources aren't portable to +	big-endian architectures. To fix this, EndianFix() will swap +	the high and low bytes of startSector and sectorCount in a +	dir entry on a big-endian arch (and leave them alone on a little- +	endian arch). Must be called just after reading, and just before +	writing. + +	The Intel x86 arch and the Atari's 6502 both happen to be +	little-endian, which is why Ken could ignore the endianness +	issue in the original MS-DOS sources. + */ +#define LITTLE_END 0 +#define BIG_END 1 + +static int InitEndian() { +	/* code based on Wikipedia "Endianness" entry */ +	union { +		short s; +		char c[sizeof(short)]; +	} un; + +	un.s = 0x0102; + +	if(sizeof(short) == 2) { +		if(un.c[0] == 1 && un.c[1] == 2) +			return BIG_END; +		else if(un.c[0] == 2 && un.c[1] == 1) +			return LITTLE_END; +	} + +	printf("WARNING: Can't determine endianness of this platform!\n"); +	printf("Assuming little-endian, hoping for the best. Expect trouble.\n"); +	return LITTLE_END; +} + +static void EndianFix(AtariDosDirEntryPtr entry) { +	static int endian = -1; +	unsigned short tmp; + +	if(endian == -1) +		endian = InitEndian(); + +	/* don't do anything on little-endian platforms */ +	if(endian == LITTLE_END) +		return; + +	tmp = entry->startSector; +	entry->startSector = ((tmp & 0xff) << 8) | ((tmp & 0xff00) >> 8); + +	tmp = entry->sectorCount; +	entry->sectorCount = ((tmp & 0xff) << 8) | ((tmp & 0xff00) >> 8); +} + +/****************************************************************** +SetVerbose - Sets verbose flag, returns last value of flag +******************************************************************/ + +int SetVerbose( int verb ) +   { +   int last; + +   last = verbose; +   verbose = verb; +   return(last); +   } + + + +/****************************************************************** + OpenAtr - opens ATR file specified for read/write (if writeable). +           Returns Atr Pointer if successful, 0 if not +******************************************************************/ + +AtrFilePtr OpenAtr(char *file ) +   { +   AtrFilePtr atr; +   int bytes; +   unsigned short signature; + +   atr = malloc(sizeof(AtrFile)); + +   atr->dosType = DOS_ATARI; /* assume atari dos disk */ + + +   atr->atrIn = fopen(file, "rb+"); +   if ( !atr->atrIn ) +      { +      free(atr); +      return 0; +      } +   bytes = fread(&hdr, 1, 16, atr->atrIn); +   if ( !bytes ) +      { +      free(atr); +      return 0; +      } +    +   signature = hdr.idLow | hdr.idHigh << 8; +   atr->imageSize = 16L * (hdr.paraLow | hdr.paraHigh * 256L | hdr.paraHigher * 65536L); +   atr->secSize = hdr.secSizeLow | hdr.secSizeHigh << 8;  +   atr->crc = hdr.crc1 | hdr.crc2 * 256L | hdr.crc3 * 65536L | hdr.crc4 *256L * 65536L ; +   atr->sectorCount = atr->imageSize / atr->secSize; +   atr->flags = hdr.flags; +   atr->writeProtect = atr->flags&1; +   atr->authenticated = (atr->flags >> 1) & 1; +    +   if ( atr->sectorCount > 721 )  +      atr->dosType = DOS_MYDOS; + +   if ( signature == 0x296 ) +      return atr; +   else +      { +      free(atr); +      return 0; +      } +   return atr; +   } + + +/****************************************************************** + CloseAtr - closes ATR file specified in an Atr Pointer from  +            and Atr Open.  Returns 0 if successful +******************************************************************/ + +int CloseAtr( AtrFilePtr atr ) +   { +   if ( atr ) +      return(fclose(atr->atrIn)); +   else +      return 1; +    } + + +/****************************************************************** + ReadSector - Reads specified sector from the ATR file specified +              info buffer which must be big enough for the sector +              size of teh file.  Returns number of bytes read or +              0 if error. +******************************************************************/ + +int ReadSector(AtrFilePtr atr, unsigned short sector, char *buffer) +   { +   unsigned long pos; +   size_t bytes; +                                                              +   if ( !atr )                                                +      {                                                       +      lastAtariError = 12;                                    +      return 0;                                               +      }             +/* calculate offset into file */                                           +   if ( atr->secSize > 128 && sector > 3 ) +      pos = (unsigned long)(sector-4) * atr->secSize + 400L; +   else +      pos = (unsigned long)(sector-1) * 128L + 16; + +/* position file pointer at that offset */ +   if ( fseek(atr->atrIn, pos, SEEK_SET) ) +      { +      lastAtariError = 13; +      return 0; +      } + +/* read the data */ +   bytes = fread(buffer, 1, atr->secSize, atr->atrIn); +   if ( bytes & 127 ) +      { +      lastAtariError = 14; +      return 0; +      } +   return bytes; +   } + +/****************************************************************** + WriteSector - Writes specified sector from the ATR file specified +               from buffer specified.  Returns number of bytes +               written or 0 if error.  Image must be writeable. +******************************************************************/ + +int WriteSector(AtrFilePtr atr, unsigned short sector, char *buffer) +   { +   unsigned long pos; +   size_t bytes; + +   if ( !atr ) +      { +      lastAtariError = 12; +      return 0; +      } + +/* calculate offset into file */ +   if ( atr->secSize > 128 && sector > 3 ) +      pos = (unsigned long)(sector-4) * atr->secSize + 400L; +   else +      pos = (unsigned long)(sector-1) * 128L + 16; + +/* set file pointer to that position */ +   if ( fseek(atr->atrIn, pos, SEEK_SET) ) +      { +      lastAtariError = 13; +      return 0; +      } + +/* sector # to high? */ +   if ( pos + atr->secSize > atr->imageSize ) +      { +      lastAtariError = 15; +      return 0; +      } + +/* write the data */ +   bytes = fwrite(buffer, 1, atr->secSize, atr->atrIn); +   if ( bytes & 127 ) +      { +      lastAtariError = 14; +      return 0; +      } +   return bytes; +} + +/****************************************************************** + CreateAtr - Creates an ATR file with parameters specified.  Sector +             size must be a multiple of 128 bytes.  Return 0 for +             success +******************************************************************/ + +int CreateAtr( char *file, unsigned short sectors,  +               unsigned short sectorSize ) +   { +   FILE *fp; +   AtrHeader hdr = {0}; +   unsigned long imageSize; +   int bytes; + +/* sector size must be a multiple of 128 */ +   if ( sectorSize & 127 ) +      return 1; +/* determine the file size for the image */ + +   if ( sectorSize > 128 && sectors > 2) +      imageSize = (unsigned long)(sectorSize-3) * sectors + 384; +   else +      imageSize = (unsigned long)sectorSize * sectors; + +/* create the file */ +   fp = fopen(file, "wb"); +   if ( !fp ) +      return 1; + +/* set up the ATR header */ +   hdr.idHigh = 0x02; +   hdr.idLow = 0x96; +   hdr.paraLow = (imageSize >> 4) & 255; +   hdr.paraHigh = (imageSize >> 12) & 255;  +   hdr.paraHigher = imageSize >> 20; +   hdr.secSizeLow = sectorSize & 255; +   hdr.secSizeHigh = sectorSize >> 8; +   bytes = fwrite(&hdr, 1, 16, fp); +   if ( bytes != 16 ) +      return 1; + +/* seek to last position needed in file - 1 */ +   if ( fseek(fp,(unsigned long)sectors * sectorSize - 1 , SEEK_SET) ) +      return 1; +/* write one null byte */ +   if ( fputc( 0, fp ) == EOF ) +      return 1; +   if ( fclose(fp) ) +      return 1; +   return 0; +   } +    +/****************************************************************** + GetAtrInfo - returns info for an open ATR image via pointers. +              non 0 returned is error.  +******************************************************************/ + +int GetAtrInfo( AtrFilePtr atr, unsigned short *sectorSize, +                unsigned short *sectorCount, byte  *protected) +   { +   if ( !atr ) +      return 1; +/* duh */ +   *sectorSize = atr->secSize; +   *sectorCount = atr->sectorCount; +   *protected = atr->writeProtect; +   return 0; +   } + + + + + +/*-----------------------------------------------------------------*/ +/*   ATARI 8-bit File IO routines                                  */ +/*-----------------------------------------------------------------*/ + +/****************************************************************** + MakeFileName - Creates a filename.ext string from a zero padded +                raw fileName and extender.  Result is stored in +                string pointed to be result.  There is no return +                value. +******************************************************************/ + +void MakeFileName( char *result, char *fileName, char *extender ) +   { +   int i; +    +   for(i=0; i<8; i++) +      { +      if (fileName[i] == ' ' || !fileName[i] ) +         break; +      *(result++) = fileName[i]; +      }       +   *(result++) = '.'; +   for(i=0; i<3; i++) +      { +      if (extender[i] == ' ' || !extender[i] ) +         break; +      *(result++) = extender[i]; +      }       +   *(result++) = 0; +   } + + +/****************************************************************** + PatternMatch - Returns 1 if fileName+extender matches pattern in +                pattern. Wildcards are the standard '?' and '*' +                as supported by all Atari Dos's.  Returns 0 if +                it does not match. +******************************************************************/ +int PatternMatch( char *pattern, char *fileName, char *extender) +   { +   int i=0; +   char file[13]; + +	/* 20070518 bkw: Special case: "*" and "*.*" always match anything */ +	if(strcmp(pattern, "*.*") == 0 || strcmp(pattern, "*") == 0) +		return 1; + +   MakeFileName(file, fileName, extender); + +   while (*pattern && file[i] ) +      { +      if ( !file[i] && *pattern ) +         return 0; +      if ( file[i] && !*pattern ) +         return 0; + +      if ( *pattern == '*') +         { +         while ( file[i] && file[i] != '.') +            i++; +         while ( *pattern && *pattern != '.') +            pattern++; +         if ( file[i] == '.' && *pattern == '.' ) +            { +            pattern++; +            i++; +            continue; +            } +         continue; +         } + +      if ( *pattern == '?' && file[i] != '.' ) +         { +         i++; +         pattern++; +         continue; +         } + +      if ( toupper(*pattern) != file[i] ) +         return 0; + +      i++;  +      pattern++; +      } + +   if ( !*pattern && !file[i] ) +      return 1; +   else +      return 0; +   } + + +/****************************************************************** + AtariFindFirst - Finds first match for pattern and sets struct +                  with file information.  returns 0 for success, +                  -1 if not found, other for error.  This is  +                  similiar to _dosfindfist in the DOS world. +******************************************************************/ + +int AtariFindFirst( char *atrName, unsigned attrib, +    char *pattern, AtariFileInfoPtr fileInfo ) +   { +   char buffer[256]; +   AtrFilePtr atr; +   int i,j; +   AtariDosDirEntryPtr dirEntry; +   unsigned short sectorSize, sectorCount; +   byte protected; + +/* open the ATR image */ +   atr = OpenAtr(atrName); +   if ( atr == NULL ) +      return 2; + +/* Get some info about the ATR image and save */ +   if ( GetAtrInfo( atr, §orSize, §orCount, &protected) ) +      { +      free(atr); +      return 3; +      } + +/* look for the file in the directory, if found initilize the fileInfo +   structure with data from the directory sector */ + +   for( i = firstDirSector, fileInfo->fileNo = 0; i <= lastDirSector; i++ ) +      { +      if (! ReadSector(atr, (unsigned short) i, buffer) ) +         return 4; +      for( j=0; j< dirEntriesPerSector; j++, fileInfo->fileNo++ ) +         { +         dirEntry = (AtariDosDirEntryPtr)(buffer + dirEntrySize * j ); +			EndianFix(dirEntry); +         fileInfo->locked = (dirEntry->flag & LOCKED_FLAG) ? 1 : 0; +         if (dirEntry->flag & DELETED_FLAG ) +            continue;  +         if ( (/* (dirEntry->flag == DOS25EXT_FLAGS) || */ (dirEntry->flag & INUSE_FLAG)) && +					PatternMatch(pattern, +             dirEntry->fileName, dirEntry->extender) ) +            { +            fileInfo->flag = dirEntry->flag; +            fileInfo->startSector = dirEntry->startSector; +            fileInfo->sectorCount = dirEntry->sectorCount; +            fileInfo->dirSector = i; +            fileInfo->dirEntry = j; +            fileInfo->attrib = attrib; +            fileInfo->pattern = pattern; +            fileInfo->atrName = atrName; +            MakeFileName( fileInfo->fileName, dirEntry->fileName, +                dirEntry->extender); +            if ( CloseAtr(atr) ) +                return 5; +            return( 0 ); /* success */ +            } +         } +      } +   if ( CloseAtr(atr) ) +      return 6; + +   return -1; +   } + +/****************************************************************** + AtariFindNext - Returns next matching file after previous  +                 AtariFindFirst or AtariFindNext call.  The fileinfo +                 structure passed should not be altered from the +                 previous call.  Also the ATR file name and pattern +                 from the initial AtariFindFirst call must still be +                 in scope. Similiar to _dosfindnext in DOS world. +******************************************************************/ + +int AtariFindNext( AtariFileInfoPtr fileInfo ) +   { +   char buffer[256]; +   AtrFilePtr atr; +   int i,j; +   AtariDosDirEntryPtr dirEntry; +   unsigned short sectorSize, sectorCount; +   byte protected; + +   atr = OpenAtr(fileInfo->atrName); +   if ( atr == NULL ) +      return 1; + +   if ( GetAtrInfo( atr, §orSize, §orCount, &protected) ) +      { +      free(atr); +      return 2; +      } +   i = fileInfo->dirSector; +   j = fileInfo->dirEntry; + +   j++; +   if ( j >= dirEntriesPerSector ) +      { +      j=0; +      i++; +      } + +   for( ; i <= lastDirSector; i++ , j = 0) +      { +      if (! ReadSector(atr, (unsigned short) i, buffer) ) +         return 3; +      for( ; j< dirEntriesPerSector; j++, fileInfo->fileNo++ ) +         { +         dirEntry = (AtariDosDirEntryPtr)(buffer + dirEntrySize * j ); +			EndianFix(dirEntry); +         fileInfo->locked = (dirEntry->flag & LOCKED_FLAG) ? 1 : 0; +         if (dirEntry->flag & DELETED_FLAG ) +            continue;  +         if ( (dirEntry->flag & INUSE_FLAG) && PatternMatch(fileInfo->pattern, +             dirEntry->fileName, dirEntry->extender) ) +            { +            fileInfo->flag = dirEntry->flag; +            fileInfo->startSector = dirEntry->startSector; +            fileInfo->sectorCount = dirEntry->sectorCount; +            fileInfo->dirSector = i; +            fileInfo->dirEntry = j; +            MakeFileName( fileInfo->fileName, dirEntry->fileName, +                dirEntry->extender); +            if ( CloseAtr(atr) ) +               return 4; +            return( 0 ); +            } +         } +      } +   if ( CloseAtr(atr) ) +      return 5; + +   return -1; +   } + + +/****************************************************************** + OpenAtariFile - Opens file in an ATR image in the mode specified +                 (ATARI_OPEN_READ, ATARI_OPEN_WRITE, or +                 ATARI_OPEN_DIR.  Returns pointer to atari file +                 structure or 0 on error.  +******************************************************************/ + +AtariFilePtr OpenAtariFile( char *atrName, char *fileName, byte mode) +   { +   AtariFilePtr atFile; +   byte protected; +   unsigned short sectorSize; +   unsigned short sectorCount; +   AtariFileInfo fileInfo; + +/* bad open mode? */ +   if ( mode != ATARI_OPEN_READ && mode != ATARI_OPEN_WRITE && +        mode != ATARI_OPEN_DIR ) +      { +      lastAtariError = 2; +      return NULL; +      } + +   atFile = malloc(sizeof(AtariFile)); +/* open the atr image */ +   atFile->atr = OpenAtr(atrName); +   if ( atFile->atr == NULL ) +      { +      free(atFile); +      lastAtariError = 1; +      return NULL; +      } +/* get some info on the ATR file and store */ +   if ( GetAtrInfo( atFile->atr, §orSize, §orCount, &protected) ) +      { +      CloseAtr(atFile->atr); +      free(atFile); +      lastAtariError = 3; +      return NULL; +      } + +/* set file parameters */ +   atFile->sectorSize = sectorSize; +   atFile->openFlag = mode; +   atFile->eofFlag = 0; + +/* is ATR write protected? (APE extension?) */ +   if ( protected && (mode & ATARI_OPEN_WRITE) ) +      { +      CloseAtr(atFile->atr); +      free(atFile); +      lastAtariError = 4; +      return NULL; +      } + +/* read directory, find start sector and number of sectors and set +   in atFile.  Initialize current sector to start sector also */ + +   if ( AtariFindFirst(atrName, 0, fileName, &fileInfo) ) +      { +      lastAtariError = 5; +      return NULL; +      } + +/* is the file the ATR is lcoated in write protected? */    +   if ( fileInfo.locked && (mode & ATARI_OPEN_WRITE) ) +      { +      lastAtariError = 6; +      return NULL; +      } + +/* set some file info data in the structure */ +   atFile->startSector = atFile->currentSector = fileInfo.startSector; +   atFile->fileNo = fileInfo.fileNo; +   atFile->numberOfSectors = fileInfo.sectorCount; +   atFile->openFlag = mode; +   atFile->currentOffset = 0; +   if (sectorSize == 128) +      atFile->sectorLinkOffset = 125; +   else if (sectorSize == 256 ) +      atFile->sectorLinkOffset = 253; +   else +      { +      lastAtariError = 7; +      return NULL; +      } +   return atFile; +   } + + +/****************************************************************** + ReadAtariFile - reads bytes bytes from the open atari file specified +   in atFile and stores them in buffer.  buffer must be big enough. +   Returns bytes actually read.  +******************************************************************/ + +long ReadAtariFile( AtariFilePtr atFile, char *buffer, long bytes ) +{ +	/* int lastSector = 0; */ +   long bytesRead = 0; + +   if ( !bytes || atFile->eofFlag) +      return 0; +   if ( !(atFile->openFlag & ATARI_OPEN_READ) ) +      return 0; +   if ( !atFile->currentOffset ) +      { +      /* read sector */ +      if (ReadSector(atFile->atr, atFile->currentSector, atFile->sectorBuffer) != atFile->sectorSize ) +         { +         if ( !lastAtariError ) +            lastAtariError = 19; +         return 0; +         } +      if ( atFile->sectorSize == 128 ) +         atFile->bytesData = atFile->sectorBuffer[atFile->sectorLinkOffset+2] +         & 127; +      else +         atFile->bytesData = atFile->sectorBuffer[atFile->sectorLinkOffset+2];  +      } +   while( bytes ) +      { +      while ( atFile->currentOffset < atFile->bytesData && bytes) +         { +         *(buffer++) = atFile->sectorBuffer[atFile->currentOffset++]; +         bytes--; +         bytesRead++; +         } + +      if ( bytes ) +         { +         /* read next sector */ +         atFile->currentOffset = 0; +         if (atFile->atr->dosType == DOS_MYDOS) +            atFile->currentSector = +                (atFile->sectorBuffer[atFile->sectorLinkOffset] << 8) | +                atFile->sectorBuffer[atFile->sectorLinkOffset+1]; +         else /* assume atari dos */ +            atFile->currentSector = +                ((atFile->sectorBuffer[atFile->sectorLinkOffset] & 3) << 8) | +                (atFile->sectorBuffer[atFile->sectorLinkOffset+1]); + +         if (!atFile->currentSector ) +            { +            atFile->eofFlag = 1; +            return bytesRead; +            } + +         ReadSector(atFile->atr, atFile->currentSector, atFile->sectorBuffer); +         if ( atFile->sectorSize == 128 ) +            atFile->bytesData = atFile->sectorBuffer[atFile->sectorLinkOffset+2] & 127; +         else +            atFile->bytesData = atFile->sectorBuffer[atFile->sectorLinkOffset+2];  +         } + +      } +   return bytesRead; +   } + + +/****************************************************************** + CloseAtariFile - Closes Atari File  +******************************************************************/ + +int CloseAtariFile( AtariFilePtr atFile ) +   { +   int stat; +   /* simple enough */ +   stat = CloseAtr( atFile->atr ); +   free( atFile ); +   return stat; +   } + + +/****************************************************************** + EofAtariFile - Returns 1 if at EOF of atari file, 0 if not  +******************************************************************/ + +int EofAtariFile( AtariFilePtr atFile ) +   { +   /* simple enough */ +   return atFile->eofFlag; +   } + +/****************************************************************** + AtariDirectory - Displays atari directory of disk image to screen +                  return 0 for success.  atrName is the ATR file +                  name, pattern is mask to use.  use "*.*" for all +                  files.  Wide if non zero displays actual file +                  length instead of just a sector count. +******************************************************************/ + +int AtariDirectory( char *atrName, char *pattern) +   { +   char buffer[256]; +   char fileName[14]; +   byte protected; +   unsigned short sectorSize; +   unsigned short sectorCount; +   AtrFilePtr atr; +   int i,j,cnt = 0; +   char locked; +   long fileSize; +   AtariDosDirEntryPtr dirEntry; + +   atr = OpenAtr(atrName); +   if ( atr == NULL ) +      return 1; + +   if ( GetAtrInfo( atr, §orSize, §orCount, &protected) ) +      { +      free(atr); +      return 1; +      } +    +   printf("sector size = %hu    sector count = %hu\n\n", sectorSize, +       sectorCount); + + +   printf("\nDirectory of '%s':\n\n", atrName); + +   if ( !wide ) +      { +      printf("no f filename ext  secs  startSec\n"); +      printf("-- - -------- ---  ----  --------\n"); +      } +   else +      { +      printf("no f filename ext  secs  length  startSec\n"); +      printf("-- - -------- ---  ----  ------  --------\n"); +      } +   for( i = firstDirSector; i <= lastDirSector; i++ ) +      { +		char printbuf[101]; +		int done = 0; +      if (! ReadSector(atr, (unsigned short) i, buffer) ) +         return 1; +      for( j=0; j< dirEntriesPerSector; j++ ) +         { +         dirEntry = (AtariDosDirEntryPtr)(buffer + dirEntrySize * j ); +			EndianFix(dirEntry); +         locked = (dirEntry->flag & LOCKED_FLAG) ? '*' : ' '; +         if (dirEntry->flag & DELETED_FLAG ) +            locked = 'D';  +			else if (dirEntry->flag & MYDOSDIR_FLAG ) { +            locked = ':';  +			} else if(dirEntry->flag == DOS25EXT_FLAGS) { +				locked = '<'; +			} +         if ( (dirEntry->flag == DOS25EXT_FLAGS) || +					((dirEntry->flag & (INUSE_FLAG | MYDOSDIR_FLAG)) && +					PatternMatch(pattern, dirEntry->fileName, dirEntry->extender)) ) +            { +            if ( wide ) +               { +               CloseAtr(atr); +               MakeFileName(fileName, dirEntry->fileName, dirEntry->extender); +					fileSize = AtariFileSize(atrName, fileName); +					if(fileSize < 0) +						sprintf(printbuf, "??"); +					else +						sprintf(printbuf, "%-6ld", fileSize); + +               atr = OpenAtr(atrName); +               if ( !atr ) +                  return 1; +               printf("%2u %c %-8.8s %-3.3s  %4.3hu  %-6s  %hu\n", cnt, locked, +                  dirEntry->fileName, dirEntry->extender, +                  dirEntry->sectorCount, printbuf, dirEntry->startSector); +               } +            else +               printf("%2u %c %-8.8s %-3.3s  %4.3hu  %hu\n", cnt, locked, +                  dirEntry->fileName, dirEntry->extender, +                  dirEntry->sectorCount, dirEntry->startSector); +            }  else { +					/* 20070518 bkw: Atari DOS stops at the first "never used" +						dirent, so do the same here.  */ +					done = 1; +					break; +				} +         cnt++; +         } +		if(done) break; +      } + +   if ( CloseAtr(atr) ) +      return 1; + +   return 0; +   } + + +/****************************************************************** + AtariFileSize - Returns size of atari file or -1 on error +******************************************************************/ + +long AtariFileSize( char *atrFile, char *fileName ) +   { +   long count = 0; +   long bytes; +   static char buffer[16]; +   AtariFilePtr input; + +   /* open the atari file on the ATR image */ +   input = OpenAtariFile(atrFile, fileName, ATARI_OPEN_READ); +   if ( input == NULL ) +      return -1;   +   /* count how many bytes we can actually read */ +   while( (bytes=ReadAtariFile(input, buffer, sizeof(buffer))) > 0 ) +      count+= bytes;  +   CloseAtariFile(input); +   return(count); +   } + + +/****************************************************************** + ExtractAtariFile - returns no. files extracted, -no for error. +                    file is stored with same name in dosPath +                    directory.  (don't add the trailing '\'). +                    Wildcards are allowed for atari file. Use NULL +                    for dosPath to extract to current directory +******************************************************************/ + +int ExtractAtariFile( char *atrFile, char *fileName, char *unixPath ) +{ +   int count = 0; +   long bytes, bytesOut; +   static char buffer[16]; +   AtariFilePtr input; +   char outName[4096]; +   FILE *output; +   AtariFileInfo info; +    + +   if ( !AtariFindFirst(atrFile, 0, fileName, &info) ) +      { +      do { +         if ( unixPath != NULL) +            { +            strcpy(outName, unixPath); +            strcat(outName,"/"); +            } +         else +            outName[0] = 0; +         strcat(outName, info.fileName); + +			/* 20070518 bkw: Get rid of trailing dots for files with no extension */ +			if(outName[strlen(outName)-1] == '.') +				outName[strlen(outName)-1] = '\0'; +          +         output = fopen(outName, "wb"); +         if (output == NULL ) +            { +            lastAtariError = 30; +            return -count-1; +            } +         input = OpenAtariFile(atrFile, info.fileName, ATARI_OPEN_READ); +         if ( input == NULL ) +            { +            return -count-1;   +            } +         if ( verbose ) +            printf("Extracting '%s'...", outName); +         while( (bytes=ReadAtariFile(input, buffer, sizeof(buffer))) > 0 ) +            { +            bytesOut = fwrite(buffer, 1, (int)bytes, output); +            if ( bytes != bytesOut ) +               { +               fclose( output ); +               CloseAtariFile(input); +               lastAtariError = 31; +               if (verbose ) +                  printf("\n"); +               return -count-1; +               } +            } +         fclose( output ); +         CloseAtariFile(input); +         if ( verbose ) +            printf(" done\n"); +         count ++; +         } while ( !AtariFindNext(&info) ); +      } +   else +      { +      return 0; +      } +   return(count); +} + + +/****************************************************************** + UpdateAtariFileNo - For atari dos, will fix the file no in each +                     sector within the file.  For use after a +                     directory is sorted.  returns 0 for success +******************************************************************/ + +int FixAtariFileNo( char *atrName, char *fileName, int fileNo ) +{ +	/* int cnt=0; */ +   AtariFilePtr atFile; + +   atFile = OpenAtariFile( atrName, fileName, ATARI_OPEN_READ); +   if ( atFile == NULL ) +      return 1; + +   if ( atFile->atr->dosType != DOS_ATARI ) +      { +      CloseAtariFile(atFile); +      return 0; +      } + + +   while (atFile->currentSector)  +      {    +      if (ReadSector(atFile->atr, atFile->currentSector, sectorBuffer) != atFile->sectorSize ) +         { +         if ( !lastAtariError ) +            lastAtariError = 19; +         CloseAtariFile(atFile); +         return 1; +         } + +      /* set the file no in the file */ +      sectorBuffer[atFile->sectorLinkOffset] &= 3; +      sectorBuffer[atFile->sectorLinkOffset] |= (atFile->fileNo<<2); + +      /* write the sector */ +      if (WriteSector(atFile->atr, atFile->currentSector, sectorBuffer) != atFile->sectorSize ) +         { +         if ( !lastAtariError ) +            lastAtariError = 19; +         CloseAtariFile(atFile); +         return 1; +         } + +      /* get next sector in link */ +      atFile->currentSector = +             ((sectorBuffer[atFile->sectorLinkOffset] & 3) << 8) | +             sectorBuffer[atFile->sectorLinkOffset+1]; +      } +   CloseAtariFile(atFile); +   return 0; +   } + + + + + + + +static int ClearAtariDirectory( char *file ); + + +/****************************************************************** + SortAtariDir -  +******************************************************************/ + +int SortAtariDir( char *atrName ) +   { +   AtrFilePtr atr; +   char *pos; +   AtariFileInfoPtr files[64]; +   AtariFileInfo info; +   AtariDosDirEntryPtr entry; +   int offset; +   unsigned short sector;    + +   int i, cnt = 0; + +   /* read file info for all files, allocate memory and store in array */ + +   if ( !AtariFindFirst(atrName, 0, "*.*", &info) ) +      { +      do { +         files[cnt] = malloc( sizeof(info) ); +         memcpy( files[cnt], &info, sizeof(info) ); +         cnt ++; +         } while ( !AtariFindNext(&info) ); +      } +   else +      { +      return 1; +      } + +   /* sort the files by name */ + +   qsort( (void *)files, (size_t) cnt, (size_t) sizeof(AtariFileInfoPtr), CompareName ); + +   /* clear out the directory */ +   if ( ClearAtariDirectory(atrName) ) +      return 1; + +   /* write the entries in sorted order to the directory sectors */ + +   offset = 0; +   sector = firstDirSector; + +   atr = OpenAtr( atrName ); + +   for( i=0; i<cnt; i++ ) +      { +      entry = (AtariDosDirEntryPtr) (sectorBuffer + offset ); +      entry->startSector = files[i]->startSector; +      entry->sectorCount = files[i]->sectorCount; +      entry->flag = files[i]->flag; +		EndianFix(entry); +      pos = strchr( files[i]->fileName, '.' ); + +		/* 20070518 bkw: init to all spaces, else you get filenames +			like "DOS\0\0\0\0\0SYS" (\0 shows up as Atari heart character) */ +		memset(entry->fileName, ' ', 8); +		memset(entry->extender, ' ', 3); + +      if ( pos != NULL) +         { + +         strncpy( entry->fileName, files[i]->fileName,  +                  min(pos-files[i]->fileName,8) ); +         strncpy( entry->extender, pos+1, 3 );      +         } +      else +         { +         strncpy( entry->fileName, files[i]->fileName, 8); +         } +      offset += 16; +      if (offset >= 128) +         { +         if ( WriteSector( atr, sector, sectorBuffer) != atr->secSize ) +            { +            CloseAtr( atr ); +            return 1; +            } +         sector ++; +         offset = 0; +         memset(sectorBuffer, 0, sizeof(sectorBuffer)); +         }       +      } +   if ( offset > 0 ) +      if ( WriteSector( atr, sector, sectorBuffer) != atr->secSize ) +         { +         CloseAtr( atr ); +         return 1; +         } + +   CloseAtr( atr ); + + +   /* This should have no effect on Mydos extended format disks */ +   for( i=0; i<cnt; i++ ) +      { +      if ( FixAtariFileNo( atrName, files[i]->fileName, i) ) +         return 1; +      free( files[i] ); +      } +   return 0; +   } + +/* function for above used as arg to qsort */ +static int CompareName( const void *a, const void *b ) +   { +   AtariFileInfoPtr aa = *(AtariFileInfoPtr *)a, +                    bb = *(AtariFileInfoPtr *)b; + +   return strcmp( aa->fileName, bb->fileName ); +   } + +/******************************************************************* +ClearAtariDirectory - internal routine +*******************************************************************/ + +static int ClearAtariDirectory( char *file ) +   { +   AtrFilePtr atr; +   int i;  +   +   memset(sectorBuffer, 0, sizeof(sectorBuffer) ); +   atr = OpenAtr( file ); +    +   for( i = firstDirSector; i <= lastDirSector; i++ ) +      if ( WriteSector(atr, i, sectorBuffer) != atr->secSize ) +         return 1; +   return 0; +   CloseAtr(atr); +   } + + +/******************************************************************** + CreateBootAtr - creates a minimally sized bootable ATR image from +                 an atari executable.  The executable must not need +                 DOS to run. +********************************************************************/ + +int CreateBootAtr( char *atrName, char *fileName) +   { +   unsigned long fileSize; +   unsigned long sectorCnt; +   AtrHeader hdr; +   unsigned long paras; +   FILE * atrFile, *inFile; +   size_t padding, bytes, bytes2; +   struct stat fileInfo; +   int status; +	int first = 1; + +/* get file's size */ + +   status = stat(fileName, &fileInfo); +   if ( status ) +      return 11; +   fileSize = (unsigned long) fileInfo.st_size; +   if ( !fileSize ) +      return 12; + +/* determine number of sectors required  */ + +   sectorCnt = (unsigned short) ((fileSize + 127L) / 128L + 3L); +   paras = sectorCnt * 16; + +/* create ATR header */ +   memset(&hdr, 0, sizeof(hdr)); +   hdr.idLow      = (byte) 0x96; +   hdr.idHigh     = (byte) 0x2; +   hdr.paraLow    = (byte) (paras & 0xFF); +   hdr.paraHigh   = (byte) ((paras >> 8) & 0xFF); +   hdr.paraHigher = (byte) ((paras >> 16) & 0xFF); +   hdr.secSizeLow = (byte) 128; + +/* open output file */ +   atrFile = fopen(atrName, "wb"); +   if ( atrFile == NULL ) +      return 1; + +/* Write the ATR Header */ +   bytes = fwrite(&hdr, 1, sizeof(hdr), atrFile); +   if ( bytes != sizeof(hdr) ) +      { +      fclose(atrFile); +      return 2; +      } + +/* plug the file size into the boot sectors at offset 9 (4 bytes)*/ +   bootData[9]  = (byte)(fileSize & 255); +   bootData[10] = (byte)((fileSize >> 8) & 255); +   bootData[11] = (byte)((fileSize >> 16) & 255); +   bootData[12] = 0; + +/* write the three boot sectors */ +   bytes = fwrite(bootData, 1, 384, atrFile); +   if ( bytes != 384 ) +      { +      fclose(atrFile); +      return 6; +      } + +/* open the input file and copy/append the file's data to output file */ + +   inFile = fopen(fileName, "rb"); +   if ( inFile == NULL ) +      { +      fclose(atrFile); +      return 13; +      } + +   bytes = 384; +   while (bytes == 384) +      { +      bytes = fread(bootData, 1, 384, inFile); +      if ( !bytes ) +         break; + +		/* 20070518 bkw: Make sure it really is an Atari bin load file */ +		if(first) { +			if((bootData[0] != 0xff) && (bootData[1] != 0xff)) { +				fclose(inFile); +				fclose(atrFile); +				return 20; +			} + +			first = 0; +		} + +      bytes2 = fwrite(bootData, 1, bytes, atrFile); +      if ( bytes != bytes2 ) +         { +         fclose(inFile); +         fclose(atrFile); +         return 19; +         } +      } +   if ( !feof(inFile) ) +      { +      fclose(inFile); +      fclose(atrFile); +      return 19; +      } + +  fclose(inFile);  + + +/* pad to even sector size (data has no meaning) */ +   padding = (size_t) ((sectorCnt-3) * 128 - fileSize );  +   if ( padding ) +      { +      bytes = fwrite(bootData, 1, padding, atrFile); +      if ( bytes != padding ) +         { +         fclose(atrFile); +         return 7; +         } +      }   + +/* close output */ +   fclose(atrFile); + +   return 0; +   } + +/******************************************************************** +ExtractExeFromBootAtr - undoes a CreateBootAtr by extracting the +                        original executable +returns 0 for error, or file length in bytes of file extracted +!!This function needs to have code added to distinguish error types. +********************************************************************/ + +long ExtractExeFromBootAtr( char *atrName, char *fileName) +   { +   FILE *atrFile, *exeFile; +   unsigned char *buffer; +   AtrHeader hdr = {0}; +	/* long fileSize; */ +   size_t bytes,bytes2,readCnt; +   unsigned long  fSize, size; + +/* get some memory */ +   buffer = malloc(384); +   if ( !buffer) +      return 0; + +/* open the atr file */ +   atrFile = fopen(atrName, "rb"); +   if ( !atrFile ) +      { +      free(buffer); +      return 0; +      } + +/* read Atr header */ + +   if ( fread(&hdr, 1, 16, atrFile) != 16 ) +      { +      free(buffer); +      fclose(atrFile); +      return 0; +      } + +/* verify it is an ATR file */ + +   if ( hdr.idHigh != 0x02 || hdr.idLow != 0x96 ) +      { +      free(buffer); +      fclose(atrFile); +      return 0; +      } + +/* read first 3 (boot) sectors */ + +   if ( fread(buffer, 1, 384, atrFile) != 384 ) +      { +      free(buffer); +      fclose(atrFile); +      return 0; +      } + +/* set the file size in bootData from the file so we can compare*/ +   bootData[9]   = buffer[9]; +   bootData[10]  = buffer[10]; +   bootData[11]  = buffer[11]; +   bootData[12]  = buffer[12]; + +/* check if ATR was created by MakeBootAtr */ +   if ( memcmp(buffer, bootData, 384) ) +      { +      free(buffer); +      fclose(atrFile); +      return 0; +      } +/* Get size of file to extract */ +   fSize = size = ((unsigned long)buffer[9]|(((unsigned long)buffer[10])<<8)|(((unsigned long)buffer[11])<<16)); + +/* Open output file */ +   exeFile = fopen(fileName, "wb"); +   if ( !exeFile ) +      { +      fclose(atrFile); +      free(buffer); +      return 0; +      } +/* copy 'size' bytes from the Atr file to the exe file */    +   bytes = 384; +   while (bytes == 384 && fSize) +      { +      readCnt = min(384, fSize); +      bytes = fread(buffer, 1, readCnt, atrFile); +      if ( !bytes ) +         break; +      bytes2 = fwrite(buffer, 1, bytes, exeFile); +      if ( bytes != readCnt ) +         { +         fclose(exeFile); +         fclose(atrFile); +         free(buffer); +         return 0; +         } +      fSize -= bytes; +      } + +/* clean up and get out of here */ +   fclose(exeFile); +   fclose(atrFile); +   free(buffer); + +   return size; +   } + + diff --git a/ksiders/atr.h b/ksiders/atr.h new file mode 100644 index 0000000..53ca6be --- /dev/null +++ b/ksiders/atr.h @@ -0,0 +1,65 @@ +/* Copyright 1997 Ken Siders */ + +#ifndef ATR_H_INCLUDED +#define ATR_H_INCLUDED + +/* constants */ +#define ATR_HEADER_SIZE 16 + + +/* typedefs */ +typedef unsigned char byte; + + +/* structure definitions */ + +struct S_HDR +{ +byte idLow, idHigh; +byte paraLow, paraHigh; +byte secSizeLow, secSizeHigh; +byte paraHigher; +byte crc1, crc2, crc3, crc4; +byte unused1, unused2, unused3, unused4; +byte flags; +}; + +typedef struct S_HDR AtrHeader; + +struct S_AtrFile { +   FILE *atrIn; +   unsigned long  imageSize; +   unsigned short secSize; +   unsigned long crc; +   unsigned long sectorCount; +   byte flags; +   byte writeProtect; +   byte authenticated; +   unsigned short currentSector; +   unsigned char dosType; +}; + +typedef struct S_AtrFile AtrFile; +typedef AtrFile *AtrFilePtr;  + + +/* function prototypes */ +AtrFilePtr OpenAtr(char *file ); + +int CloseAtr( AtrFilePtr atr ); +int ReadSector(AtrFilePtr atr, unsigned short sector, char *buffer); +int WriteSector(AtrFilePtr atr, unsigned short sector, char *buffer); +int CreateAtr( char *file, unsigned short sectors,  +               unsigned short sectorSize ); +int GetAtrInfo( AtrFilePtr atr, unsigned short *sectorSize, +                unsigned short *sectorCount, byte  *protected); +int CreateBootAtr( char *atrName, char *fileName); +long ExtractExeFromBootAtr(char *, char *); + +int SortAtariDir( char *atrName ); +int SetVerbose( int verb ); +int ExtractAtariFile( char *atrFile, char *fileName, char *dosPath ); + +#endif + + diff --git a/ksiders/atr.txt b/ksiders/atr.txt new file mode 100644 index 0000000..44c2b06 --- /dev/null +++ b/ksiders/atr.txt @@ -0,0 +1,521 @@ +All files Copyright 1997 Ken Siders
 +
 +Ken's ATR manipulation C library.  This has only been used under Microsoft
 +C/C++ version 8.0.  It will probably work on 7.0 and possibly earlier
 +versions.  You are on your own for porting to other compilers.
 +
 +With Microsoft C, you must use the /Zp option to pack structure members
 +on byte boundries.  I have no idea how this translates to other compilers.
 +
 +
 +To Do
 +1 Clean up warnings + make more portable
 +2 Allow opening write-protected ATRs
 +3 Allow more than one reference to an ATR file to be opened so more 
 +   than one atari file can be opened at once.
 +4 More specific error returns
 +5 Implement XFD handling
 +6 Create documentation
 +7 Optimize if necessary
 +8 Implement DCM images (maybe)
 +
 +----------------------------------------------------------------------------
 +
 +This source is a work in progress and in distributed for those wanting
 +to write ATR related programs.  I had planned to tidy them up a lot before
 +releasing them, but have been sidetracked by other projects.  Feel free to
 +use them in your own freeware and public domain programs if credit is given.
 +
 +These have all been compiled with Microsoft C version 8.0.  They should
 +compile with 7.0 and possibly earlier versions.  They may need 
 +some tweaking for use on other compilers.  The /Zp option must be used
 +on the Microsoft compiler to pack structures on byte boundries.  I don't
 +know how this is done on other compilers.
 +
 +Files:
 +The file that does all of the work is ATR.C.  The other programs do some
 +basic processing and call fucntions in ATR.C to do the work.  
 +
 +The other C files, all build the ATR utilities that are on my Atari
 +web page.  They, of course must be linked with the main ATR file.
 +
 +There are two header files: ATR.H and ATRDOS.H both of which will be
 +required by most programs.  ATR.H contains definitions for ATR image related
 +functions.  ATRDOS.H contains definitions for referencing Mydos and
 +Atari Dos files located on ATR images.  Hopefully the short descriptions
 +in the source are enough to allow one to figure out what each function does.
 +There is also a third header file with the Boot disk routine.
 +
 +
 +Note:  You cannot open write protected images yet and you can only have
 +one ATR open at a time.  If you Open an ATR and then call a function like
 +ATRDirectory, an error will result.  You must Close the ATR first, call
 +the function and then reopen the ATR.  This also means you can't have two
 +files open in a single ATR at the same time.  This will hopefully be
 +rectified soon.  Good Luck.
 +
 +
 +
 +mailto:  ken_siders@compuserve.com
 +http://ourworld.compuserve.com/homepages/ken_siders/atari.htm
 +
 +
 +PS: I still am looking for info on other disk formats such as SpartaDOS.
 +Also info on subdirectory format, how to distinquish Dos 2.5 enhanced
 +density and MyDos enhanced density, etc.....
 +
 +-----------------------------------------------------------------------------
 +
 +***********************************************************************
 +Structures
 +***********************************************************************
 +ATR File pointer structure definition.  Most of this info comes from
 +the ATR header:
 +
 +struct S_AtrFile {
 +   FILE *atrIn;                     pointer to the file.
 +   unsigned long  imageSize;        image size
 +   unsigned short secSize;          sector size: 128/256
 +   unsigned long crc;               crc - ATR extension (not used)
 +   unsigned long sectorCount;       number of sectors in image
 +   byte flags;                      flags byte from ATR image.
 +   byte writeProtect;               image write protected?
 +   byte authenticated;              ATR extension (not used)
 +   unsigned short currentSector;    don't know what I have this here for.
 +   unsigned char dosType;           ataridos, mydos?  see atr.h for constants
 +};
 +typedef struct S_AtrFile AtrFile;
 +typedef AtrFile *AtrFilePtr; 
 +
 +
 +Atari File pointer structure definition.  This is info required to read and
 +write atari files in an ATR image as well as related functions.
 +
 +struct S_AtariFile
 +   {
 +   AtrFilePtr atr;                  atr file is in
 +   unsigned short startSector;      start sector of file
 +   unsigned short currentSector;    current sector pointer
 +   unsigned short sectorSize;       sector size: 128 or 256
 +   unsigned short numberOfSectors;  number of sectors in file
 +   unsigned long fileSize ;         size of file in bytes
 +   byte openFlag;                   flag used in AtariOpenFile
 +   byte eofFlag;                    set if at eof
 +   short currentOffset;             current offset into sector
 +   short bytesData;                 bytes of data in current sector
 +   short sectorLinkOffset;          offset to link data.  usually 125 or 253
 +   short fileNo;                    file No for Atari Dos
 +   unsigned char sectorBuffer[256]; buffer with current sector
 +   };
 +typedef struct S_AtariFile AtariFile;
 +typedef AtariFile * AtariFilePtr;
 +
 +
 +***********************************************************************
 +Image Functions - These functions are used for low level access to
 +                  ATR disk images.
 +***********************************************************************
 +
 +OpenAtr      AtrFilePtr OpenAtr(char *file )
 +
 +   Description:     
 +       Opens an ATR image so sectors can be read or written or information
 +       on the image can be obtained.
 +     
 +   Parameters:
 +       file - the filename of the ATR.  Use the full drive and pathname if
 +              the file is not in the current directory.  You must add the
 +              .ATR extension.
 +
 +   Returns:
 +       An ATR file pointer that is used with other functions to access the
 +       image's data.
 +
 +
 +CloseAtr     int CloseAtr( AtrFilePtr atr )
 +
 +   Description:     
 +       Closes an ATR image opened with OpenATR.
 +    
 +   Parameters:
 +       atr - the ATR file pointer that was returned by the OpenAtr function.
 +
 +   Returns:
 +       0 for success, 1 if an error occured.
 +
 +         
 +ReadSector   int ReadSector(AtrFilePtr atr, unsigned short sector,
 +                            char *buffer)
 +
 +   Description:
 +       Reads specified sector from the ATR file specified into buffer which
 +       must be big enough for the sector size of the ATR image file (128 or
 +       256 bytes).
 +
 +   Parameters:
 +       atr - Atr file pointer returned from an OpenAtr function call.
 +       sector - Sector number to read.
 +       buffer - A pointer that points to a buffer large enough to hold a
 +            sector of data.  Usually you want this to be 256 bytes.
 +
 +   Returns:
 +       Number of bytes read or 0 if error.
 +
 +
 +WriteSector  int WriteSector(AtrFilePtr atr, unsigned short sector,
 +                             char *buffer)
 +
 +   Description:
 +       Writes specified sector from the ATR file specified from buffer
 +       specified. 
 +
 +   Parameters:
 +       atr - Atr file pointer returned from an OpenAtr function call.
 +       sector - Sector number to write.
 +       buffer - A pointer that points to a buffer containing the sector
 +                data to write.  Usually 128 or 256 bytes.
 +
 +   Returns:
 +       Number of bytes written or 0 if error.
 +
 +
 +CreateAtr   int CreateAtr( char *file, unsigned short sectors, 
 +               unsigned short sectorSize )
 +
 +   Description: 
 +       Creates an new ATR file with parameters specified.  
 +
 +   Parameters:
 +       file - Name of the ATR file to create.  If file exists it will
 +              be overwritten.
 +       sectors - The number of sectors in the image.  Common values are
 +                 720 (single/double density) or 1040 (1050 double) but
 +                 smaller an huge images may also be created.
 +       sectorSize - This should be 128 (single/1050 double density) or
 +                    256 (double density).
 +
 +   Returns:
 +       0 for success, 1 on failure.
 +
 +
 +GetAtrInfo   int GetAtrInfo( AtrFilePtr atr, unsigned short *sectorSize,
 +                unsigned short *sectorCount, byte  *protected)
 +
 +   Descriptions:
 +       Returns the sector size, and sector count for an image.  It also
 +       returns info if the disk is write protected or not.  (Write protect
 +       status is not fully implemented yet.)
 +
 +   Parameters:
 +       atr - the ATR file pointer that was returned by the OpenAtr function.
 +       sectorSize - A pointer to a variable in which to return the sector
 +                    size. 
 +       sectorCount - A pointer to a variable in which to return the sector
 +                    count. 
 +       protected - A pointer to a variable in which to return the write
 +                   protect status.  1 = protected, 0 = not.  If the image
 +                   write protected or if the APE extension bit for write
 +                   protect is set, this will be 1.  Not implemented yet.
 +
 +    Returns: 0 for success, 1 if error. 
 +
 +
 +AtariFindFirst  int AtariFindFirst( char *atrName, unsigned attrib,
 +                                    char *pattern,
 +                                    AtariFileInfoPtr fileInfo )
 +   Description:
 +       Finds first match for pattern and sets struct with file information.
 +       For those using Microsoft C compilers, this is similiar to
 +       _dosfindfirst.
 +
 +   Parameters:
 +       atrName - Name of ATR image in which to look for the file.
 +       attrib - Not used yet.  Use 0.
 +       pattern - The atari file to look for.  * and ? are accepted as normal
 +                 atari wildcards.  Use only and 8.3 file name, no drive or
 +                 directory specifications.
 +       fileInfo - A pointer to your file info structure in which to return
 +                  the information.  This structure will also be use by
 +                  the AtariFindNext function.
 +        
 +   Returns:
 +        0 if a match was found.
 +        -1 if a match was not found.
 +        a positive number if an error occurred.     
 +
 +
 +AtariFindNext  int AtariFindFirst( AtariFileInfoPtr fileInfo )
 +
 +   Description:
 +       Searches for the next match after a previous AtariFindFirst or 
 +       AtariFindNext.  Sets struct with file information.  For those using
 +       Microsoft C compilers, this is similiar to _dosfindnext.  The
 +       fileInfo structure should not be modified prior to calling this
 +       function.
 +
 +   Parameters:
 +       fileInfo - A pointer to your file info structure in which to return
 +                  the information.  This structure should still have
 +                  unmodified info from the last AtariFindFirst or 
 +                  AtariFindNext function call.
 +        
 +   Returns:
 +        0 if a match was found.
 +        -1 if a match was not found.
 +        a positive number if an error occurred.     
 +        
 +CreateBootAtr - int CreateBootAtr( char *atrName, char *fileName)
 +
 +   Description:
 +        Will create a minimally sized bootable ATR image from an Atari
 +        Executable.  The ATR file will be just long enough to hold
 +        three boot sectors and the file's data.  The executable must
 +        consist of only one file and not need DOS for any reason.  Note:
 +        Not all Atari computer and peripheral emulators may support
 +        non-standard sized images.  When booting from the image, the
 +        screen will turn red if an error occurs. 
 +
 +   Parameters:     
 +        atrName - The ATR file name.
 +        fileName - The name of the MSDOS file to convert.
 +         
 +   Returns:
 +        0 for success.
 +
 +
 +ExtractExeFromBootAtr - long ExtractExeFromBootAtr( char *atrName,
 +                        char *fileName)
 +
 +   Description:
 +        Undoes a CreateBootAtr by extracting the original executable from
 +        the ATR image.
 +
 +   Parameters:     
 +        atrName - ATR file name of a disk created with CreateBootAtr.
 +        fileName - The name of the MSDOS file to write the output to.
 +        
 +   Returns:
 +        Returns 0 for error, or file length in bytes of file extracted.
 +        An error will result if the file was not created with CreateBootAtr.
 +
 +
 +***********************************************************************
 +Dos Functions - These functions are used to reference atari files 
 +                stored on ATR disk images.
 +***********************************************************************
 +
 +OpenAtariFile - AtariFilePtr OpenAtariFile( char *atrName, char *fileName,
 +                                            byte mode)
 +
 +   Description:
 +       Opens file in an ATR image in the mode specified: ATARI_OPEN_READ,
 +       ATARI_OPEN_WRITE, or ATARI_OPEN_DIR.  ATARI_OPEN_DIR is not supported
 +       yet.
 +
 +   Parameters:
 +       atrName - Name of ATR image in which to look for the file.
 +       fileName - Filename of the atari file in the ATR image to open.              
 +       mode - ATARI_OPEN_READ to open the file for read, ATARI_OPEN_WRITE
 +              to open it for write.  "Or" the two together for both.
 +              ATARI_OPEN_DIR is not implemented yet.
 +
 +   Returns:
 +        An Atari file pointer that can be used in functions to read or
 +        write from the file.  NULL is returned on error.
 +
 +
 +ReadAtariFile  - long ReadAtariFile( AtariFilePtr atFile, char *buffer,
 +                                     long bytes )
 +
 +   Description:
 +        Reads bytes bytes from an open atari file (opened with OpenAtariFile).
 +
 +   Parameters:     
 +   atFile - An Atari file pointer that was set from an OpenAtariFile function
 +            call
 +   buffer - A pointer to a buffer to read the bytes into.  Must be big 
 +            enough to hold the number of bytes requested.
 +   bytes - Number of bytes to read.
 +     
 +   Returns:
 +        Number of bytes actually read.  May be less than bytes if EOF was
 +        reached.  You can use EofAtariFile to see if the EOF was reached
 +        or if an error occurred.
 +
 +
 +CloseAtariFile - int CloseAtariFile( AtariFilePtr atFile )
 +
 +   Description:
 +        Closes an atari file opened with OpenAtariFile.
 +
 +   Parameters:
 +        atFile - An atari file pointer used in an OpenAtariFile function
 +                 call.
 +
 +   Returns:
 +        0 if successful.
 +        
 +
 +EofAtariuFile - int EofAtariFile( AtariFilePtr atFile )
 +
 +   Description:
 +        Determines if pointer is at the end of an atari file.
 +
 +   Parameters:
 +        atFile - An atari file pointer returned from an OpenAtariFile
 +                 function call.
 +
 +   Returns:
 +        Returns 1 if at EOF of atari file, 0 if not 
 +
 +
 +AtariDirectory - int AtariDirectory( char *atrName, char *pattern)
 +
 +   Description:
 +        Displays atari directory of disk image to screen.  The disk image
 +        must be Atari Dos, MyDos, or compatable.
 +
 +   Parameters:
 +        atrName - The ATR file name.
 +        pattern - filename mask to use.  use "*.*" for all files.
 +        
 +   Returns:
 +        0 for no errors.
 +
 +
 +AtariFileSize long AtariFileSize( char *atrFile, char *fileName )
 +
 +   Description:
 +        Get the actual length in bytes of an atari file in an ATR image.
 +
 +   Parameters:     
 +        atrName - The ATR file name.
 +        fileName - The atari filename in 8.3 to look for.  No wildcards.
 +
 +   Returns:
 +        Length of file in bytes or -1 for error.
 +
 +
 +ExtractAtariFile - int ExtractAtariFile( char *atrFile, char *fileName,
 +                                       char *dosPath )
 +
 +   Description:
 +        Extracts an Atari file from an ATR image.  Atari Dos and MyDos
 +        formats are supported for the image.
 +     
 +   Parameters:     
 +        atrName - The ATR file name.
 +        fileName - Atari filename in 8.3 format.  Wildcards * and ? are
 +                   allowed.  If verbose is on, files will be displayed
 +                   as they are extracted.
 +        dosPath - Directory to store the file in.  File is stored with same
 +                  name in dosPath directory.  (don't add the trailing '\').
 +                  Use NULL for dosPath to extract to current directory.
 +
 +   Returns:
 +        number of file extracted.  If the result is negative, an error 
 +        occured but the Absolute value of that number of files were
 +        extracted successfully before the error occurred.
 +
 +
 +FixAtariFileNo - int FixAtariFileNo( char *atrName, char *fileName,
 +                 int fileNo )
 +        
 +   Description - For atari dos, will fix the file no in each sector within
 +                 the file.  Used internally after a directory is sorted but
 +                 their may be other uses.  For larger MyDos disks the 
 +                 function has no effect.  I currently don't know how to
 +                 distinquish DOS 2.5 1050 double density disks and Mydos
 +                 disks so this may not work on Dos 2.5 1050 double density
 +                 disks.
 +
 +   Parameters:     
 +        atrName - The ATR file name.
 +        fileName - Atari filename in 8.3 format to fix.  No wildcard's 
 +                   allowed.
 +        fileNo - File number to give the file.  This could probably be
 +                 made to be automatic.  
 +         
 +   Returns:
 +        0 for success.
 +
 +
 +SortAtariDir - int SortAtariDir( char *atrName )
 +
 +   Description:
 +        Sorts the files in an ATR image.  BUT: 1. May not work on Dos 2.5
 +        1050 double density disks.  2.  Doesn't allow DOS.SYS and DUP.SYS,
 +        or other files to be specified not to be sorted.  
 +
 +   Parameters:     
 +        atrName - The ATR file name.
 +         
 +   Returns:
 +        0 for success.
 +
 +
 +
 +***********************************************************************
 +Other Functions - Other functions.
 +***********************************************************************
 +
 +
 +SetVerbose    int SetVerbose( int verb )
 +
 +   Description:     
 +       Used to set verbose flag to 1 (on) or 0 (off).  Currently the only
 +       function that uses this is ExtractAtariFile.
 +
 +   Parameters:
 +       verb - 1 for verbose, 0 for not verbose
 +
 +   Returns:
 +       Previous state of verbose flag.
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 diff --git a/ksiders/atrdir.1 b/ksiders/atrdir.1 new file mode 100644 index 0000000..6e2d0bf --- /dev/null +++ b/ksiders/atrdir.1 @@ -0,0 +1,65 @@ +.TH ATRDIR "1" "April 2007" "atrdir" "Ken Siders' Atari 8-bit Tools" +.SH NAME +\fBatrdir\fR \- print the directory of an ATR disk image +.SH SYNOPSIS +\fBatrdir\fR \fIimagefile.atr\fR [\fIwildcard\fR] +.SH DESCRIPTION +\fBatrdir\fR prints the directory of an Atari DOS 2.x or MyDOS compatible +ATR disk image. Sample output: +.PP +.nf +--------------------------------------------------------------------- +Directory of dos_20s.atr:*.*: +sector size = 128    sector count = 720 + + +Directory of 'dos_20s.atr': + +no f filename ext  secs  length  startSec +-- - -------- ---  ----  ------  -------- + 0 * DOS      SYS   039  4875    4 + 1 * DUP      SYS   042  5126    43 + 2   AUTORUN  SYS   001  88      85 +--------------------------------------------------------------------- +.fi +.PP +The \fIf\fR column contains an asterisk (\fI*\fR) for a locked file, +a \fID\fR for a deleted file, \fI:\fR for a MyDOS subdirectory, +\fI<\fR for a DOS 2.5 file that uses sectors above 720, +or nothing for any other file. +.PP +\fIwildcard\fR is an optional glob pattern, such as \fI*.sys\fR. If not +given, the default is \fI*.*\fR. \fIwildcard\fR is case insensitive; +\fI*.txt\fR is equivalent to \fI*.TXT\fR. Most shells will require the argument +to be quoted, to avoid the shell's normal wildcard expansion. The +globbing semantics are similar to those of Atari DOS or POSIX sh, but +are not identical to either. +.PP +\fBatrdir\fR does not take any other options. +.SH NOTES +.PP +DOS 2.5 disk images are not fully supported. Specifically, \fBatrdir\fR +is unable to determine the size of files that use sectors above 720 (those +that are listed with \fI<\fR). Instead, the size will be reported as \fB??\fR. +.PP +MyDOS large disk images (aka hard disk images) are supported. +.PP +XFD format images are not supported. +.PP +The current version of \fBatrdir\fR cannot determine the size of a MyDOS +directory. Instead, the size is reported as \fB??\fR. +.PP +\fBatrdir\fR cannot print the contents of MyDOS subdirectories. +.PP +Exit status is zero for success, non-zero for failure. +.SH AUTHOR +Ken Siders <\fBatari8bit@columbus.rr.com\fR> +.PP +Man page by B. Watson <\fBurchlay@urchlay.com\fR> +.SH SEE ALSO +\&\fIatrextr\fR\|(1), \&\fImakeatr\fR\|(1), \&\fIsortatr\fR\|(1), +\&\fIunmakatr\fR\|(1). +.PP +Ken Siders Atari 8\-bit page: +.br +http://atari.ksiders.tzo.com/a8emulators.html diff --git a/ksiders/atrdir.c b/ksiders/atrdir.c new file mode 100644 index 0000000..62920c0 --- /dev/null +++ b/ksiders/atrdir.c @@ -0,0 +1,89 @@ +/* Copyright 1997 Ken Siders */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "atr.h" +#include "atdos.h" + +void help(void) +   { +   printf("usage: atrdir atrname.atr [filespec]\n"); +   printf("\n"); +   printf("\n\n"); +   } + + +int main( int argc, char **argv) +   { +   AtrFilePtr atr; +   int minCnt; +   char option; +   static char mask[80]; + + +   printf("AtrDir Version 0.9u (c)1997 Ken Siders\n"); +	printf("Ported and modified by B. Watson, 2007\n"); +   printf("This program may be freely distributed\n\n"); + +   if (argc < 2) +      { +      help(); +      exit(2); +      } +    +   if (argv[1][0] == '-') +      { +      option = argv[1][1]; +      minCnt = 3; +      } +   else +      { +      option = 0; +      minCnt = 2; +      } + +   if ( argc != minCnt && argc != minCnt + 1) +      { +      help(); +      exit(4); +      } + +   if (option && option != 'W' && option != 'w' ) +      { +      help(); +      exit(5); +      } + +   atr = OpenAtr(argv[minCnt-1]); +   if (atr == 0) +      { +      printf("Error reading ATR file: %s\n", argv[1]); +      exit(2); +      } +   else +      { +      CloseAtr(atr); +      } + +   if (argc == minCnt) +      strcpy(mask, "*.*"); +   else +      strcpy(mask, argv[minCnt]); +   printf("Directory of %s:%s:\n", argv[minCnt-1], mask); +   AtariDirectory( argv[minCnt-1], mask); +       +    + + + + + +	/* printf("\n%d file(s)\n", count); */ + +	exit(0); +   } + + + + diff --git a/ksiders/atrextr.1 b/ksiders/atrextr.1 new file mode 100644 index 0000000..9912f76 --- /dev/null +++ b/ksiders/atrextr.1 @@ -0,0 +1,64 @@ +.TH ATREXTR "1" "April 2007" "atrextr" "Ken Siders' Atari 8-bit Tools" +.SH NAME +\fBatrextr\fR \- extract files from an ATR image + +.SH SYNOPSIS +\fBatrextr\fR \fIimagefile.atr\fR [\fIfile\fR] [\fIdir\fR] + +.SH DESCRIPTION +\fBatrextr\fR extracts one or more files from an Atari DOS 2.x or MyDOS +compatible ATR disk image. Extracted files are written to the current +directory. +.PP +\fIfile\fR is an optional filename or wildcard pattern, +such as \fIautorun.sys\fR or \fI*.sys\fR. If not +given, the default is \fI*.*\fR. \fIfile\fR is case insensitive: +\fIreadme.txt\fR is equivalent to \fIREADME.TXT\fR, and +\fI*.txt\fR is equivalent to \fI*.TXT\fR. If a wildcard is used, +most shells will require the argument +to be quoted, to avoid the shell's normal wildcard expansion. The +wildcard semantics are similar to those of Atari DOS or POSIX sh, but +are not identical to either. +.PP +\fIdir\fR is the directory to extract files to. If omitted, the default +is the current directory. If \fIdir\fR is to be given, \fIfile\fR must +also be given (although it may be specified as \fI""\fR, equivalent +to \fI"*.*"\fR). +.PP +\fBatrextr\fR does not take any other options. +.SH NOTES +DOS 2.5 disk images are not fully supported. Specifically, \fBatrextr\fR +is unable to extract files that use sectors above 720 (those +that are listed with \fI<\fR, in \fBatrdir\fR or Atari DOS 2.5). These +files will be silently skipped, exactly as Atari DOS 2.0S does when reading +a 2.5 enhanced density disk. +.PP +MyDOS subdirectories are not supported. Only files in the root directory +of a disk image can be extracted. +.PP +MyDOS large disk images (aka hard disk images) are supported, though +without subdirectory support, \fBatrextr\fR can't extract most of the +files in a typical hard disk image. +.PP +XFD format images are not supported. Neither are SpartaDOS, Atari DOS 3/4, +DOS XE, or other non-standard DOS formats. +.PP +There should be options to translate Atari EOL characters to and from +UNIX newlines, and to convert the extracted filenames to lowercase. +.PP +Exit status is zero if all files were extracted successfully, or +non-zero if any errors occurred. In case of a non-zero return, +some files may still have been extracted (though some or all of them +may be truncated or corrupt). +.SH AUTHOR +Ken Siders <\fBatari8bit@columbus.rr.com\fR> +.PP +Man page by B. Watson <\fBurchlay@urchlay.com\fR> + +.SH SEE ALSO +\&\fIatrdir\fR\|(1), \&\fImakeatr\fR\|(1), \&\fIsortatr\fR\|(1), +\&\fIunmakatr\fR\|(1). +.PP +Ken Siders Atari 8-bit page: +.br +http://atari.ksiders.tzo.com/a8emulators.html diff --git a/ksiders/atrextr.c b/ksiders/atrextr.c new file mode 100644 index 0000000..2aeb898 --- /dev/null +++ b/ksiders/atrextr.c @@ -0,0 +1,63 @@ +/* Copyright 1997 Ken Siders */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#include "atr.h" +#include "atdos.h" + +int main( int argc, char **argv) { +	AtrFilePtr atr; +	int stat = 0, ret = 0; +	char *file = "*.*"; +	char *path = NULL; + +	printf("AtrExtr Version 0.9u (c)1997 Ken Siders\n"); +	printf("Ported and modified by B. Watson, 2007\n"); +	printf("This program may be freely distributed\n\n"); + +	if(argc < 2 || argc > 4) { +		printf("usage: atrextr atrname.atr [file] [dir]\n" +				"Wildcards may be used for file (default: *.*)\n" +				"dir will be created, if it does not exist\n"); +		exit(-1); +	} + +	atr = OpenAtr(argv[1]); +	if(atr == 0) { +		printf("Error reading ATR file: %s\n", argv[1]); +		CloseAtr(atr); +		exit(2); +	} + +	CloseAtr(atr); + +	if(argc >= 3 && argv[2][0]) +		file = argv[2]; + +	if(argc == 4) { +		path = argv[3]; +		mkdir(path, 0777); /* ignore errors (ExtractAtariFile() will fail instead) */ +	} + +	while ( !stat ) { +		SetVerbose(1); +		stat = ExtractAtariFile( argv[1], file, path ); +		SetVerbose(0); +	} + +	if( stat < 0 ) { +		printf("\nError encountered when extracting file(s)\n"); +		printf("some files may have been extracted incorrectly\n"); +		stat = -stat; +		ret = 1; +	} + +	printf("\n%d file(s) extracted\n", stat); + +	exit(ret); +} + + diff --git a/ksiders/atrsrc.zip b/ksiders/atrsrc.zip Binary files differnew file mode 100644 index 0000000..7a70fb5 --- /dev/null +++ b/ksiders/atrsrc.zip diff --git a/ksiders/kboot.h b/ksiders/kboot.h new file mode 100644 index 0000000..02576f5 --- /dev/null +++ b/ksiders/kboot.h @@ -0,0 +1,61 @@ +/* Copyright 1997 Ken Siders */ + +/* This is the code used in the first three (boot) sectors when +   creating an ATR from an Atari executable + +History: +    Ver 0.01  07/17/97 - Initial version  +*/ + +  +unsigned char bootData[384] = { +      0x00, 0x03, 0x00, 0x07, 0x14, 0x07, 0x4C, 0x14, +      0x07, 0x00, 0x00, 0x00, 0x00, 0xA9, 0x46, 0x8D, +      0xC6, 0x02, 0xD0, 0xFE, 0xA0, 0x00, 0xA9, 0x6B, +      0x91, 0x58, 0x20, 0xD9, 0x07, 0xB0, 0xEE, 0x20, +      0xC4, 0x07, 0xAD, 0x7A, 0x08, 0x0D, 0x76, 0x08, +      0xD0, 0xE3, 0xA5, 0x80, 0x8D, 0xE0, 0x02, 0xA5, +      0x81, 0x8D, 0xE1, 0x02, 0xA9, 0x00, 0x8D, 0xE2, +      0x02, 0x8D, 0xE3, 0x02, 0x20, 0xEB, 0x07, 0xB0, +      0xCC, 0xA0, 0x00, 0x91, 0x80, 0xA5, 0x80, 0xC5, +      0x82, 0xD0, 0x06, 0xA5, 0x81, 0xC5, 0x83, 0xF0, +      0x08, 0xE6, 0x80, 0xD0, 0x02, 0xE6, 0x81, 0xD0, +      0xE3, 0xAD, 0x76, 0x08, 0xD0, 0xAF, 0xAD, 0xE2, +      0x02, 0x8D, 0x70, 0x07, 0x0D, 0xE3, 0x02, 0xF0, +      0x0E, 0xAD, 0xE3, 0x02, 0x8D, 0x71, 0x07, 0x20, +      0xFF, 0xFF, 0xAD, 0x7A, 0x08, 0xD0, 0x13, 0xA9, +      0x00, 0x8D, 0xE2, 0x02, 0x8D, 0xE3, 0x02, 0x20, +      0xAE, 0x07, 0xAD, 0x7A, 0x08, 0xD0, 0x03, 0x4C, +      0x3C, 0x07, 0xA9, 0x00, 0x85, 0x80, 0x85, 0x81, +      0x85, 0x82, 0x85, 0x83, 0xAD, 0xE0, 0x02, 0x85, +      0x0A, 0x85, 0x0C, 0xAD, 0xE1, 0x02, 0x85, 0x0B, +      0x85, 0x0D, 0xA9, 0x01, 0x85, 0x09, 0xA9, 0x00, +      0x8D, 0x44, 0x02, 0x6C, 0xE0, 0x02, 0x20, 0xEB, +      0x07, 0x85, 0x80, 0x20, 0xEB, 0x07, 0x85, 0x81, +      0xA5, 0x80, 0xC9, 0xFF, 0xD0, 0x10, 0xA5, 0x81, +      0xC9, 0xFF, 0xD0, 0x0A, 0x20, 0xEB, 0x07, 0x85, +      0x80, 0x20, 0xEB, 0x07, 0x85, 0x81, 0x20, 0xEB, +      0x07, 0x85, 0x82, 0x20, 0xEB, 0x07, 0x85, 0x83, +      0x60, 0x20, 0xEB, 0x07, 0xC9, 0xFF, 0xD0, 0x09, +      0x20, 0xEB, 0x07, 0xC9, 0xFF, 0xD0, 0x02, 0x18, +      0x60, 0x38, 0x60, 0xAD, 0x09, 0x07, 0x0D, 0x0A, +      0x07, 0x0D, 0x0B, 0x07, 0xF0, 0x79, 0xAC, 0x79, +      0x08, 0x10, 0x50, 0xEE, 0x77, 0x08, 0xD0, 0x03, +      0xEE, 0x78, 0x08, 0xA9, 0x31, 0x8D, 0x00, 0x03, +      0xA9, 0x01, 0x8D, 0x01, 0x03, 0xA9, 0x52, 0x8D, +      0x02, 0x03, 0xA9, 0x40, 0x8D, 0x03, 0x03, 0xA9, +      0x80, 0x8D, 0x04, 0x03, 0xA9, 0x08, 0x8D, 0x05, +      0x03, 0xA9, 0x1F, 0x8D, 0x06, 0x03, 0xA9, 0x80, +      0x8D, 0x08, 0x03, 0xA9, 0x00, 0x8D, 0x09, 0x03, +      0xAD, 0x77, 0x08, 0x8D, 0x0A, 0x03, 0xAD, 0x78, +      0x08, 0x8D, 0x0B, 0x03, 0x20, 0x59, 0xE4, 0xAD, +      0x03, 0x03, 0xC9, 0x02, 0xB0, 0x22, 0xA0, 0x00, +      0x8C, 0x79, 0x08, 0xB9, 0x80, 0x08, 0xAA, 0xAD, +      0x09, 0x07, 0xD0, 0x0B, 0xAD, 0x0A, 0x07, 0xD0, +      0x03, 0xCE, 0x0B, 0x07, 0xCE, 0x0A, 0x07, 0xCE, +      0x09, 0x07, 0xEE, 0x79, 0x08, 0x8A, 0x18, 0x60, +      0xA0, 0x01, 0x8C, 0x76, 0x08, 0x38, 0x60, 0xA0, +      0x01, 0x8C, 0x7A, 0x08, 0x38, 0x60, 0x00, 0x03, +      0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +   }; +      diff --git a/ksiders/makeatr.1 b/ksiders/makeatr.1 new file mode 100644 index 0000000..fc2ab5a --- /dev/null +++ b/ksiders/makeatr.1 @@ -0,0 +1,92 @@ +.TH MAKEATR,UNMAKATR "1" "April 2007" "makeatr, unmakatr" "Ken Siders' Atari 8-bit Tools" +.SH NAME +\fBmakeatr\fR \- convert an Atari executable to a "K-file" bootable disk +.br +\fBunmakatr\fR \- extract original executable from a disk made with \fBmakeatr\fR + +.SH SYNOPSIS +\fBmakeatr\fR \fIimagefile.atr\fR \fIatari-exe\fR +.br +\fBunmakeatr\fR \fIimagefile.atr\fR \fIatari-exe\fR + +.SH DESCRIPTION +For various reasons, it's sometimes useful to make a bootable disk image +of an Atari executable. \fBmakeatr\fR does exactly that. +.PP +If you have a bootable image made with \fBmakeatr\fR, but you've lost the +original executable, you can extract it from the image with \fBunmakatr\fR. +.PP +.SH NOTES +\fBmakeatr\fR is only useful for single\-file games or other programs that +don't need DOS disk access to run: the bootable image won't contain +any DOS at all, or even a DOS file structure (you can't read the directory). +.PP +\fBunmakatr\fR only works for images created by \fBmakeatr\fR. It is not +a general-purpose bootdisk-to-executable utility. +.PP +Disks made with \fBmakeatr\fR are recognizable when booted on the Atari, +because they display GR.0 screen with a lowercase \fIk\fR +(screen is otherwise blank). +.PP +Disk images made with \fBmakeatr\fR are only created with enough sectors +to hold the executable. AtariSIO can handle these images fine, as can +most other ATR utilities, but the smaller-than-regulation size may cause +problems with some utilities. +.PP +There is only one Atari executable format, regardless of filename extension. +All .XEX, .COM, .BIN, .EXE, etc. files for the Atari are the same file type, +regardless of the name, and regardless of what you may have read on some +forum site. Atari DOS doesn't care about the filename; it only exists for +human consumption (and for filetype association with emulators, these +days). + +.SH DIAGNOSTICS +\fBmakeatr\fR's error messages are not well documented. They consist only +of an internal error number code, listed here: +.PP +.B 1 +\- Unable to open ATR image for writing +.br +.B 2 +\- Unable to write image ATR header +.br +.B 6 +\- Unable to write boot sectors to ATR image +.br +.B 7 +\- Error while padding ATR image to an even sector size +.br +.B 11 +\- Unable to stat the input file (not found, permission denied, etc) +.br +.B 12 +\- Input file is 0 bytes in length +.br +.B 13 +\- Can't open input file +.br +.B 19 +\- Error writing to ATR image, \fBor\fR trailing junk in the input image +.br +.B 20 +\- Input file is not an Atari executable (missing 0xFF 0xFF signature) +.br +.PP +\fBunmakatr\fR reports "Error #0" for any and all errors it may encounter. +.PP +Both \fBmakeatr\fR and \fBunmakatr\fR return a 0 exit status to the caller +for success, or non-zero status for failure (and print one of the above +error messages, as well). Error messages are printed to standard \fBoutput\fR, +not standard error output. + +.SH AUTHOR +Ken Siders <\fBatari8bit@columbus.rr.com\fR> +.PP +Man page by B. Watson <\fBurchlay@urchlay.com\fR> + +.SH SEE ALSO +\&\fIatrdir\fR\|(1), \&\fIatrextr\fR\|(1), \&\fIsortatr\fR\|(1). +.PP +Ken Siders Atari 8-bit page: +.br +http://atari.ksiders.tzo.com/a8emulators.html diff --git a/ksiders/makeatr.c b/ksiders/makeatr.c new file mode 100644 index 0000000..457e0e5 --- /dev/null +++ b/ksiders/makeatr.c @@ -0,0 +1,41 @@ +/* Copyright 1997 Ken Siders */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "atr.h" +#include "atdos.h" + + +/******************************************************************** + Testing  +********************************************************************/ + + +int main( int argc, char **argv) +   { +   int stat = 0; + +   printf("MakeAtr Version 0.9u (c)1997 Ken Siders\n"); +	printf("Ported and modified by B. Watson, 2007\n"); +   printf("This program may be freely distributed\n\n"); + + +   if (argc != 3) +      { +      printf("usage: makeatr atrname.atr file\n\n"); +      } +   else +      { +      stat = CreateBootAtr( argv[1], argv[2] ); +      if ( stat ) +         printf("Error #%d encountered in conversion\n\n", stat); +      else +         printf("No errors, %s created successfully\n\n", argv[1]); +      } + +	exit(stat); + +} + + diff --git a/ksiders/sortatr.1 b/ksiders/sortatr.1 new file mode 100644 index 0000000..98301b3 --- /dev/null +++ b/ksiders/sortatr.1 @@ -0,0 +1,80 @@ +.TH SORTATR "1" "April 2007" "sortatr" "Ken Siders' Atari 8-bit Tools" +.SH NAME +\fBsortatr\fR \- sort Atari DOS directory in an ATR image + +.SH SYNOPSIS +\fBsortatr\fR \fIimagefile.atr\fR + +.SH DESCRIPTION +\fBsortatr\fR sorts the directory entries in an Atari DOS 2.0S or MyDOS +compatible ATR images. The sort is alphabetical, and the disk image +is modified in place. +.PP +\fBatrextr\fR does not take any options. +.SH WARNINGS +\fBDO NOT USE\fR this utility with DOS 2.5 disk images! +.PP +\fBDO NOT USE\fR this utility with MyDOS images containing subdirectories! +.PP +\fBDATA LOSS\fR will occur if these warnings are not heeded! The modified +directory in the image will not contain any references to DOS 2.5 files +using sectors above 720, or to MyDOS subdirectories. This effectively +\fBdeletes\fR these files from the image. +.PP +If in doubt, list the image's directory with \fBatrdir\fR. If you see +files marked with a \fI:\fR (colon) or \fI<\fR (less-than), then +\fBsortatr\fR should not be used on the image. Even if your purpose +is actually to delete these files/dirs, you should use some other +utility (or DOS on a real or emulated Atari) to delete them, because +\fBsortatr\fR doesn't free the sectors occupied by the files/dirs. +.PP +If you ignore these warnings and manage to delete files or directories +from your disk image, it should be possible to recover them with a good +Atari undelete or disk\-repair utility. Although the affected files/dirs +have been removed from the disk directory, the data sectors have not +been overwritten nor marked as free (meaning they won't be overwritten +by later write operations, unlike most "undelete" situations). +First, you have to +find the starting sector of the missing file/dir and +create a directory entry for it in the directory at sectors 36-368. You +will probably also have to change the file number in the sector link +bytes, or else delete the file in the new directory that's using the +file number of the old (deleted) file. +.PP +Further warnings: +.PP +\fBDO NOT USE\fR this utility with any non-standard (non\-AtariDOS, +non-MyDOS compatible) disk image. +.PP +Boot disks with no directory, +SpartaDOS, Atari DOS 3/4, DOS XE, or other non\-standard DOS formatted +disks might (if you're lucky) just cause an error message. If +you're not lucky, they may be corrupted. There is no easy way to +recover an image that gets damaged in this way. +.PP +\fBDO NOT USE\fR this utility with \fIany\fR image without creating a +backup first! +.PP +Any image you use with \fBsortatr\fR is modified in-place, +and no backup is made by \fBsortatr\fR. \fBAlways\fR make a backup +copy of an ATR image before you use \fBsortatr\fR on it. \fIYou have +been warned\fI. +.SH NOTES +XFD format images are not supported. +.PP +Exit status is zero if the sort was successful, or +non-zero if any errors occurred. In case of a non-zero return, +the disk image may be truncated, or its directory sectors may be +damaged. Hope you had a backup of that image! +.SH AUTHOR +Ken Siders <\fBatari8bit@columbus.rr.com\fR> +.PP +Man page by B. Watson <\fBurchlay@urchlay.com\fR> + +.SH SEE ALSO +\&\fIatrdir\fR\|(1), \&\fIatrextr\fR\|(1), \&\fImakeatr\fR\|(1), +\&\fIunmakatr\fR\|(1). +.PP +Ken Siders Atari 8-bit page: +.br +http://atari.ksiders.tzo.com/a8emulators.html diff --git a/ksiders/sortatr.c b/ksiders/sortatr.c new file mode 100644 index 0000000..394dc28 --- /dev/null +++ b/ksiders/sortatr.c @@ -0,0 +1,39 @@ +/* Copyright 1997 Ken Siders */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "atr.h" +#include "atdos.h" + +/* SortAtr */ + + +int main( int argc, char **argv) +   { +   int stat; + +   printf("SortATR v0.9  (C)1997 Ken Siders\n"); +   printf("This program may be freely distributed\n\n"); + +   if ( argc != 2 ) +      { +      printf("usage: sortatr atrname\n"); +      exit(2); +      } +   stat = SortAtariDir( argv[1] ); +   if ( stat ) +      { +      printf("Error sorting directory\n"); +      exit(3); +      } +   else +      { +      printf("no errors\n"); +      exit(0); +      } + + +} + + diff --git a/ksiders/unmakatr.c b/ksiders/unmakatr.c new file mode 100644 index 0000000..c50b55d --- /dev/null +++ b/ksiders/unmakatr.c @@ -0,0 +1,43 @@ +/* Copyright 1997 Ken Siders */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "atr.h" +#include "atdos.h" + + +/******************************************************************** + Testing  +********************************************************************/ + + +int main( int argc, char **argv) +   { +   long size = 0; + +   printf("MakeAtr Version 0.9u (c)1997 Ken Siders\n"); +	printf("Ported and modified by B. Watson, 2007\n"); +   printf("This program may be freely distributed\n\n"); + + +   if (argc != 3) +      { +      printf("usage: unmakatr atrname.atr file\n\n"); +      } +   else +      { +      size = ExtractExeFromBootAtr( argv[1], argv[2] ); +      if ( size <= 0 ) { +         printf("Error #%ld encountered in extracting\n\n", -size); +			exit(size); +		} else { +         printf("No errors, %s extracted successfully (%ld bytes)\n\n", argv[2], size); +		} +	} + +	exit(0); + +} + +  | 
