2023-04-06 20:44:16 +00:00
# ifdef _WIN32
# define _CRT_SECURE_NO_WARNINGS 1
# define _CRT_NONSTDC_NO_DEPRECATE 1 // error C4996: '_stricmp': The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name: _stricmp.
//#define stricmp _stricmp
//#pragma warning(suppress : 4996)
# endif
2017-11-06 05:55:01 +00:00
# define DEBUG_MAIN 0
# include <stdio.h> // printf()
# include <stdint.h> // uint8_t
# include <sys/stat.h> // stat
# include <stdlib.h> // exit()
# include <string.h> // memcpy()
# include <time.h> // time() localtime()
# include "itoa.comma.h"
# include "string.utils.cpp"
# include "generic.disk.cpp"
# include "prodos.utils.cpp"
# include "prodos.tools.cpp"
/*
2017-12-29 17:37:07 +00:00
TODO :
- meta < filename > Use these file attributes instead of default < file > . _META
- nometa Do not generate < file > . _META when extracting via ' get '
2017-11-06 06:23:39 +00:00
Is this still needed ?
2017-11-06 05:55:01 +00:00
- path /
*/
enum DISK_COMMANDS_e
{
DISK_COMMAND_CAT_SHORT = 0 // cat
, DISK_COMMAND_CAT_LONG // catalog
2017-11-06 06:02:42 +00:00
, DISK_COMMAND_FILE_ADD // cp - Copy host filesystem to virtual DSK
2017-11-06 05:55:01 +00:00
, DISK_COMMAND_CAT_LONG2 // dir - alias for catalog
, DISK_COMMAND_FILE_GET // get - Copy virtual DSK to host file system
, DISK_COMMAND_VOL_INIT // init
, DISK_COMMAND_CAT_NAMES // ls
, DISK_COMMAND_DIR_CREATE // mkdir
2023-04-08 15:41:51 +00:00
, DISK_COMMAND_DIR_CREATE2 // md
2017-11-06 05:55:01 +00:00
, DISK_COMMAND_FILE_DELETE // rm
, DISK_COMMAND_DIR_DELETE // rmdir
2023-04-08 15:41:51 +00:00
, DISK_COMMAND_DIR_DELETE2 // rd
2017-11-06 05:55:01 +00:00
, DISK_COMMAND_INVALID
, NUM_DISK_COMMANDS
} ;
const char * gaCommands [ NUM_DISK_COMMANDS ] =
{
" cat " // CAT__SHORT
, " catalog " // CAT__LONG
2017-11-06 06:02:42 +00:00
, " cp " // FILE_ADD
2017-11-06 16:51:45 +00:00
, " dir " // CAT__LONG2
2017-11-06 05:55:01 +00:00
, " get " // FILE_GET
, " init " // VOL__INIT
, " ls " // CAT__NAMES
, " mkdir " // DIR__CREATE
2023-04-08 15:41:51 +00:00
, " md " // DIR__CREATE2
2017-11-06 05:55:01 +00:00
, " rm " // FILE_DELETE
, " rmdir " // DIR__DELETE
2023-04-08 15:41:51 +00:00
, " rd " // DIR__DELETE2
2017-11-06 05:55:01 +00:00
, " "
} ;
2017-11-06 16:51:45 +00:00
const char * gaCommandDescriptions [ NUM_DISK_COMMANDS ] =
2017-11-06 05:55:01 +00:00
{
" Catalog (short form) " // CAT__SHORT
, " Catalog (long form) " // CAT__LONG
, " Add file(s) to volume " // FILE_ADD
2017-11-06 16:51:45 +00:00
, " Catalog (long form) " // CAT__LONG2
2017-11-06 05:55:01 +00:00
, " Extract file from volume " // FILE_GET
, " Format disk " // VOL__INIT
, " Catalog (file names only) " // CAT__NAMES
, " Create a sub-directory " // DIR__CREATE
2023-04-08 15:41:51 +00:00
, " Create a sub-directory " // DIR__CREATE2
2017-11-06 05:55:01 +00:00
, " Delete file from volume " // FILE_DELETE
, " Remove a sub-directory " // DIR__DELETE
2023-04-08 15:41:51 +00:00
, " Remove a sub-directory " // DIR__DELETE2
2017-11-06 16:51:45 +00:00
, " " // NUM_DISK_COMMANDS
} ;
const char * gaOptionsDescriptions [ NUM_DISK_COMMANDS ] =
{
// CAT__SHORT
" [<path>] Path of virtual sub-directory to view \n "
" Defaults to: / \n "
, // CAT_LONG
" [<path>] Path of virtual sub-directory to view \n "
" Defaults to: / \n "
, // FILE_ADD
2023-04-07 02:13:39 +00:00
" File type will auto-detected based on filename extension. \n "
" i.e. BAS, BIN, FNT, TXT,SYS, etc. \n "
2017-11-06 16:51:45 +00:00
" -access=$## Set access flags \n "
2023-06-13 06:24:01 +00:00
" NOTE: Defaults to $C3 \n "
2017-11-06 16:51:45 +00:00
" $80 Volume/file can be destroyed \n "
" $40 Volume/file can be renamed \n "
" $20 Volume/file changed since last backup \n "
" $04 Volume/file is invisible \n "
" $02 Volume/file can be read \n "
" $01 Volume/file can be written \n "
" -aux=$#### Set the aux address \n "
" -date=MM/DD/YY Set create date to specified date \n "
" -date=DD-MON-YY Set create date to specified date \n "
" MON is one of: \n "
" JAN, FEB, MAR, APR, MAY, JUN, \n "
" JUL, AUG, SEP, OCT, NOV, DEC \n "
" -time=HH:MMa Set create time to specified 12-hour AM \n "
" -time=HH:MMp Set create time to specified 12-hour PM \n "
" -time=HH:MM Set create time to specified 24-hour time \n "
2017-12-11 16:24:34 +00:00
" -type=<type> Set the file type to a 3 character code \n "
" i.e. BIN, SYS \n "
2017-11-06 16:51:45 +00:00
" -type=$## Force file type to one of the 256 types \n "
2017-11-07 15:48:58 +00:00
" The file type is auto-detected via extension \n "
2017-11-06 16:51:45 +00:00
" -moddate=MM/DD/YY Set last modified date to specified date \n "
" -modtime=HH:MM Set last modified date to specified time \n "
2023-04-07 02:13:39 +00:00
" <path> Destination virutal sub-directory to add to \n "
" There is no default -- it must be specified \n "
" NOTE: Options must come first \n "
2017-11-06 16:51:45 +00:00
, //CAT_LONG2
" This is an alias for 'catalog' \n "
, // FILE_GET
2023-06-13 06:23:47 +00:00
" [-boot=<file>] Optional: extract boot sector to file \n "
2017-11-06 16:51:45 +00:00
" <path> Path of virtual file to extract \n "
" NOTES: \n "
" The file remains on the virtual volume \n "
" To delete a file see ........: rm \n "
" To delete a sub-directory see: rmdir \n "
, // VOL__INIT
2023-06-13 06:23:47 +00:00
" [-boot=<file>] Optional: replace boot sector with file \n "
2017-11-06 16:51:45 +00:00
" -size=140 Format 140 KB (5 1/4 \" ) \n "
" -size=800 Format 800 KB (3 1/2 \" ) \n "
" -size=32 Format 32 MB (Hard Disk) \n "
2023-06-13 06:23:47 +00:00
" <path> Name of virtual volume. \n "
2017-11-06 16:51:45 +00:00
, // CAT__NAMES
" [<path>] Path to sub-directory to view \n "
" Defaults to: / \n "
, // DIR__CREATE
2023-04-08 15:41:30 +00:00
" NOTE: Not implemented yet! \n "
2017-11-06 16:51:45 +00:00
" <path> Destination virutal sub-directory to create \n "
" There is no default -- it must be specified \n "
2023-04-08 15:41:51 +00:00
, // DIR__CREATE2
" Alias for mkdir \n "
2017-11-06 16:51:45 +00:00
, // FILE_DELETE
" <path> Path of virtual file to delete \n "
" There is no default -- it must be specified \n "
, // DIR__DELETE
2023-04-08 15:41:30 +00:00
" NOTE: Not implemented yet! \n "
2017-11-06 16:51:45 +00:00
" <path> Path of virtual sub-directory to delete \n "
" There is no default -- it must be specified \n "
" NOTE: \n "
" You can't delete the root directory: / \n "
" -f Force removal of sub-directory \n "
" (Normally a sub-directory must be empty) \n "
2023-04-08 15:41:51 +00:00
, // DIR__DELETE2
" Alias for rmdir \n "
2023-06-13 06:24:15 +00:00
" NOTE: Not implemented yet! \n "
2017-11-06 16:51:45 +00:00
, NULL
2017-11-06 05:55:01 +00:00
} ;
2023-04-08 15:42:02 +00:00
char sPath [ 256 ] = " / " ; // TODO: What is max ProDOS path? 128 characters?
2017-11-06 05:55:01 +00:00
const char * gpPath = NULL ;
int gnDay = 0 ;
int gnMonth = 0 ;
int gnYear = 0 ;
int giOptions = 0 ; // index of arg that is 1st command
// int gnOptions = 0; // number of args minus config options
// ========================================================================
int usage ( )
{
printf (
2017-11-06 16:51:45 +00:00
" Usage: <dsk> <command> [<options>] [<path>] \n "
2017-11-06 05:55:01 +00:00
" \n "
) ;
for ( int iCommand = 0 ; iCommand < NUM_DISK_COMMANDS - 1 ; iCommand + + )
2017-11-06 16:51:45 +00:00
{
/**/ printf ( " %-7s %s \n "
, gaCommands [ iCommand ]
, gaCommandDescriptions [ iCommand ]
) ;
if ( gaOptionsDescriptions [ iCommand ] )
printf ( " %s "
, gaOptionsDescriptions [ iCommand ]
) ;
}
2017-11-06 05:55:01 +00:00
printf (
" \n "
" Where <dsk> is a virtual disk image with an extension of: \n "
" \n "
2017-11-06 16:51:45 +00:00
" .dsk (Assumes DOS3.3 sector order) \n "
" .do (DOS3.3 sector order) \n "
" .po (ProDOS sector order) \n "
2017-11-06 05:55:01 +00:00
" \n "
" NOTE: To skip always having to specify the <.dsk> name set the environment variable: \n "
" \n "
" PRODOS_VOLUME \n "
" e.g. \n "
2017-11-06 16:51:45 +00:00
" export PRODOS_VOLUME=path/to/volume.po \n "
2017-11-06 16:54:51 +00:00
" set PRODOS_VOLUME=disk.dsk \n "
2017-11-06 05:55:01 +00:00
" \n "
" Three different disk sizes are accepted for init \n "
" \n "
2023-04-07 02:13:39 +00:00
" prodosfs test.dsk init -size=140 /TEST514 # 5 1/4 \" (140 KB) \n "
" prodosfs test.dsk init -size=800 /TEST312 # 3 1/2 \" (800 KB) \n "
" prodosfs test.dsk init -size=32 /TEST32M #HardDisk ( 32 MB) \n "
2017-11-06 05:55:01 +00:00
" \n "
2023-06-13 06:23:47 +00:00
" To put a (512) boot sector file use -boot with the init command: \n "
" prodosfs test.dsk init -boot=bootsector.bin -size=140 /TEST514 \n "
" \n "
" To get a (512) boot sector file use -boot with the cp command: \n "
" prodosfs test.dsk cp -boot=bootsector.bin /TEST514 \n "
" \n "
2017-11-06 05:55:01 +00:00
" Examples: \n "
" \n "
2017-12-29 17:30:01 +00:00
" prodosfs test.dsk ls \n "
" prodosfs test.dsk cat \n "
" prodosfs test.dsk cp foo1 foo2 / \n "
" prodosfs test.dsk mkdir bar \n "
" prodosfs test.dsk cp foo2 /bar \n "
" prodosfs test.dsk get /PRODOS \n "
" prodosfs test.dsk rm /bar/foo2 \n "
" prodosfs test.dsk rmdir /bar \n "
" prodosfs test.dsk init /TEST \n "
" prodosfs b140.dsk init -size=140 /BLANK140 \n "
" prodosfs b800.dsk init -size=800 /BLANK800 \n "
" prodosfs b032.dsk init -size=32 /BLANK32 \n "
2017-11-06 05:55:01 +00:00
" \n "
) ;
return 1 ;
}
// ========================================================================
void setTimeNow ( ProDOS_FileHeader_t * entry )
{
time_t now = time ( NULL ) ;
struct tm * time = localtime ( & now ) ;
// http://www.manpages.info/macosx/ctime.3.html
gnMonth = time - > tm_mon + 1 ; // 0-11
gnDay = time - > tm_mday ; // 1-31
gnYear = time - > tm_year % 100 ;
entry - > date = ProDOS_DateToInt ( gnMonth , gnDay , gnYear ) ;
}
/*
2017-12-29 17:52:40 +00:00
TODO : Sync these up with < file > . _META ProDOS_FileExtract ( ) and getCopyConfig ( )
2017-12-29 17:37:24 +00:00
2017-11-06 16:51:59 +00:00
- access = $ # #
- aux = $ # # # #
2017-11-06 05:55:01 +00:00
- date = MM / DD / YY
2017-11-06 16:51:59 +00:00
- date = DD - MON - YY
- moddate = MM / DD / YY
- moddate = DD - MON - YY
- modtime = HR : MNa
- modtime = HR : MNp
- modtime = HH : MM
- modtime = $ # # # #
- time = HR : MNa
- time = HR : MNp
- time = $ # # # #
- time = HH : MM
2017-11-06 05:55:01 +00:00
- type = $ # #
2017-11-06 16:51:59 +00:00
- type = BIN
2017-12-29 17:52:40 +00:00
- version = $ # #
- minver = $ # #
2017-11-06 05:55:01 +00:00
*/
// @return false if fatel error
// ========================================================================
bool getCopyConfig ( ProDOS_FileHeader_t * entry , const char * arg )
{
size_t nLenPrefix = strlen ( arg ) ; // Total length of: option=val
size_t nLenSuffix = 0 ; // Length of value
const char * pVal = 0 ;
int val = 0 ;
if ( strncmp ( arg , " date= " , 5 ) = = 0 )
{
nLenSuffix = nLenPrefix - 5 ;
pVal = arg + 5 ;
// Default to current date
int mon = gnMonth ;
int day = gnDay ;
int yar = gnYear ;
//-date=MM/DD/YY
//-date=DD-MON-YR
if ( ( nLenSuffix ! = 8 ) | | nLenSuffix ! = 9 )
{
printf ( " ERROR: Invalid date. Format is MM/DD/YY or DD-MON-YR \n " ) ;
return false ;
}
if ( nLenSuffix = = 8 )
{ // 01234567
// MM/DD/YY
if ( ( pVal [ 2 ] ! = ' / ' ) | | ( pVal [ 5 ] ! = ' / ' ) )
{
printf ( " ERROR: Invalid date: Format is MM/DD/YY. e.g. 12/31/17 \n " ) ;
return false ;
}
mon = atoi ( pVal + 0 ) ;
day = atoi ( pVal + 3 ) ;
yar = atoi ( pVal + 6 ) ;
}
if ( nLenSuffix = = 9 )
{ // 012345678
// DD-MON-YY
if ( ( pVal [ 2 ] ! = ' - ' ) | | ( pVal [ 6 ] ! = ' - ' ) )
{
printf ( " ERROR: Invalid date: Format is DD-MON-YR. e.g. 01-JAN-17 \n " ) ;
return false ;
}
day = atoi ( pVal + 0 ) ;
2017-11-07 15:48:58 +00:00
mon = prodos_DateMonthToInt ( pVal + 3 ) ;
2017-11-06 05:55:01 +00:00
yar = atoi ( pVal + 7 ) ;
}
entry - > date = ProDOS_DateToInt ( mon , day , yar ) ;
2017-11-06 16:51:59 +00:00
}
else
if ( strncmp ( arg , " moddate= " , 8 ) = = 0 )
{
nLenSuffix = nLenPrefix - 8 ;
pVal = arg + 8 ;
printf ( " ERROR: Modified Time not yet implemented \n " ) ;
}
else
if ( strncmp ( arg , " modtime= " , 8 ) = = 0 )
{
nLenSuffix = nLenPrefix - 8 ;
pVal = arg + 8 ;
printf ( " ERROR: Modified Time not yet implemented \n " ) ;
2017-11-06 05:55:01 +00:00
}
else
if ( strncmp ( arg , " time= " , 5 ) = = 0 )
{
nLenSuffix = nLenPrefix - 5 ;
pVal = arg + 5 ;
2017-11-06 16:51:59 +00:00
printf ( " ERROR: Create Time not yet implemented \n " ) ;
2017-11-06 05:55:01 +00:00
}
else
if ( strncmp ( arg , " type= " , 5 ) = = 0 )
{
nLenSuffix = nLenPrefix - 5 ;
pVal = arg + 5 ;
if ( pVal [ 0 ] = = ' $ ' )
{
2017-12-11 16:24:54 +00:00
val = getHexVal ( pVal ) ; // safely ignores leading $
2017-11-06 05:55:01 +00:00
if ( val < 0x00 ) val = 0x00 ;
if ( val > 0xFF ) val = 0xFF ;
entry - > type = val ;
}
else
{
char sExt [ 4 ] ;
int nLen = string_CopyUpper ( sExt , pVal , 3 ) ;
for ( int iType = 0 ; iType < 256 ; iType + + )
{
if ( stricmp ( pVal , gaProDOS_FileTypes [ iType ] ) = = 0 )
{
entry - > type = iType ;
break ;
}
}
}
}
else
if ( strncmp ( arg , " aux= " , 4 ) = = 0 )
{
nLenSuffix = nLenPrefix - 4 ;
pVal = arg + 4 ;
2017-12-11 16:24:54 +00:00
if ( pVal [ 0 ] = = ' $ ' )
{
val = getHexVal ( pVal ) ; // safely ignores leading $
if ( val < 0x0000 ) val = 0x0000 ;
if ( val > 0xFFFF ) val = 0xFFFF ;
entry - > aux = val ;
}
2017-11-06 05:55:01 +00:00
}
else
if ( strncmp ( arg , " access= " , 7 ) = = 0 )
{
nLenSuffix = nLenPrefix - 7 ;
pVal = arg + 7 ;
val = getHexVal ( pVal ) ;
if ( val < 0x00 ) val = 0x00 ;
if ( val > 0xFF ) val = 0xFF ;
entry - > access = val ;
}
2017-11-07 15:48:58 +00:00
2017-11-06 05:55:01 +00:00
return true ;
}
// ========================================================================
bool doCopy ( ProDOS_FileHeader_t * entry , const char * filename )
{
const char * pSrcFileName = filename ;
size_t nSrcLen = strlen ( pSrcFileName ) ;
char * pExt = const_cast < char * > ( file_GetExtension ( pSrcFileName ) ) ;
char sExt [ 5 ] = " .??? " ;
size_t nExtLen = 0 ;
bool bCopiedName = false ;
// Chop extension down to leading '.' plus max 3 chars
if ( pExt )
{
size_t nLen = string_CopyUpper ( sExt , pExt , 4 ) ; // 3 char extension
pExt = sExt ;
nExtLen = nLen ;
}
2017-12-29 17:26:27 +00:00
const char * pBaseName = filename + nSrcLen ;
size_t nBaseLen = 0 ;
// Chop off preceeding directory if there is one
if ( pBaseName )
{
while ( pBaseName > filename )
{
if ( * pBaseName = = ' / ' )
break ;
pBaseName - - ;
nBaseLen + + ;
}
}
# if DEBUG_MAIN
printf ( " ---------- \n " ) ;
printf ( " Extension: %d \n " , pExt ! = NULL ) ;
printf ( " + %s \n " , pSrcFileName ) ;
printf ( " Len: %u \n " , nSrcLen ) ;
printf ( " Base: %s \n " , pBaseName ) ;
printf ( " Len: %u \n " , nBaseLen ) ;
printf ( " ---------- \n " ) ;
# endif
2017-11-06 05:55:01 +00:00
if ( nSrcLen > 15 )
{
2017-12-29 17:26:27 +00:00
nBaseLen = nSrcLen - nExtLen ;
2017-11-06 05:55:01 +00:00
// Chop off part of name until it fits
2017-12-29 17:26:27 +00:00
{
pBaseName + + ;
nBaseLen - - ;
}
2017-11-06 05:55:01 +00:00
// If we have an extension, chop the prefix preserving extension
// If no extension, chop the prefix
if ( pExt )
{
int end = nSrcLen - 4 ;
2017-12-29 17:26:27 +00:00
int len1 = string_CopyUpper ( gEntry . name + 0 , pBaseName , nBaseLen ) ;
int len2 = string_CopyUpper ( gEntry . name + end , pExt ) ;
2017-11-06 05:55:01 +00:00
gEntry . len = len1 + len2 ;
bCopiedName = true ;
}
}
if ( ! bCopiedName )
{
2023-04-06 20:44:30 +00:00
gEntry . len = ( uint8_t ) string_CopyUpper ( gEntry . name , pSrcFileName ) ;
2017-11-06 05:55:01 +00:00
}
# if DEBUG_MAIN
printf ( " Entry.name: %s \n " , gEntry . name ) ;
# endif
if ( pExt )
{
for ( int iExt = 0 ; iExt < 256 ; iExt + + )
{
const char * tExt = gaProDOS_FileTypes [ iExt ] ;
if ( tExt [ 0 ] = = ' ? ' )
continue ;
int nExtLen = 3 ;
if ( tExt [ 2 ] = = ' ' )
nExtLen = 2 ;
bool bFoundExt = true ;
for ( int i = 0 ; i < nExtLen ; i + + )
if ( sExt [ 1 + i ] ! = tExt [ i ] )
bFoundExt = false ;
if ( bFoundExt )
{
# if DEBUG_MAIN
2017-12-29 17:37:34 +00:00
printf ( " Auto-detect file type: $%02X %s \n " , iExt , tExt ) ;
2017-11-06 05:55:01 +00:00
# endif
gEntry . type = iExt ;
break ;
}
}
}
2023-06-13 06:16:55 +00:00
prodos_MetaLoad ( & gEntry ) ;
2017-11-06 05:55:01 +00:00
# if DEBUG_MAIN
2023-04-07 02:13:52 +00:00
printf ( " File Access: $%02X \n " , gEntry . access ) ;
2017-11-06 05:55:01 +00:00
# endif
bool bStatus = ProDOS_FileAdd ( gpPath , pSrcFileName , & gEntry ) ;
return bStatus ;
}
// ========================================================================
const char * getVirtualPath ( int nArg , const char * aArg [ ] , int * iArg , bool inc )
{
if ( * iArg < nArg )
{
const char * pSrc = aArg [ * iArg ] ;
char * pDst = sPath ;
int nLen = string_CopyUpper ( pDst , pSrc , 255 ) ;
if ( inc )
* iArg + + ;
return sPath ;
}
return NULL ;
}
// ========================================================================
void errorBadInterleave ( )
{
printf ( " ERROR: Unable to detect sector interleave. e.g. .do, .po, or .dsk \n " ) ;
exit ( 1 ) ;
}
void errorBadDisk ( )
{
printf ( " ERROR: Unable to read ProDOS disk: %s \n " , gpDskName ) ;
exit ( 1 ) ;
}
// ========================================================================
void readVolume ( int nArg , const char * aArg [ ] , int * iArg )
{
if ( gpDskName )
{
if ( ! DskGetInterleave ( gpDskName ) )
errorBadInterleave ( ) ;
if ( ! DskLoad ( gpDskName , ( SectorOrder_e ) giInterleaveLastUsed ) )
errorBadDisk ( ) ;
}
2017-12-29 17:25:48 +00:00
# if DEBUG_MAIN
printf ( " nArg: %d \n " , nArg ) ;
printf ( " iArg: %d \n " , * iArg ) ;
# endif
2017-11-06 05:55:01 +00:00
gpPath = getVirtualPath ( nArg , aArg , iArg , true ) ;
# if DEBUG_MAIN
2017-12-29 17:25:48 +00:00
printf ( " virtual path: %s \n " , gpPath ) ;
2017-11-06 05:55:01 +00:00
# endif
prodos_GetVolumeHeader ( & gVolume , PRODOS_ROOT_BLOCK ) ;
# if DEBUG_MAIN
printf ( " Loaded... \n " ) ;
# endif
}
// ========================================================================
int main ( const int nArg , const char * aArg [ ] )
{
2017-11-06 06:23:55 +00:00
int iArg = 1 ; // DSK is 1st arg
2017-11-06 05:55:01 +00:00
char * pathname_filename = NULL ;
char * auto_dsk_name = getenv ( " PRODOS_VOLUME " ) ;
gpDskName = auto_dsk_name ;
if ( auto_dsk_name )
{
printf ( " INFO: Using auto ProDOS disk name: %s \n " , auto_dsk_name ) ;
}
else
{
if ( iArg < nArg )
{
gpDskName = aArg [ iArg ] ;
iArg + + ;
# if DEBUG_MAIN
printf ( " Found disk name from command line: %s \n " , gpDskName ) ;
# endif
}
}
const char * pCommand = iArg < nArg
? aArg [ iArg ]
: NULL
;
int iCommand = DISK_COMMAND_INVALID ;
if ( pCommand )
for ( iCommand = 0 ; iCommand < NUM_DISK_COMMANDS - 1 ; iCommand + + )
{
if ( strcmp ( aArg [ iArg ] , gaCommands [ iCommand ] ) = = 0 )
{
iArg + + ;
break ;
}
}
# if DEBUG_MAIN
printf ( " iCommand: %d \n " , iCommand ) ;
printf ( " pCommand: %s \n " , pCommand ) ;
printf ( " pPathName %s \n " , gpPath ) ;
# endif
switch ( iCommand )
{
case DISK_COMMAND_CAT_LONG :
case DISK_COMMAND_CAT_LONG2 :
readVolume ( nArg , aArg , & iArg ) ;
ProDOS_CatalogLong ( gpPath ) ;
break ;
case DISK_COMMAND_CAT_NAMES :
readVolume ( nArg , aArg , & iArg ) ;
ProDOS_CatalogNames ( gpPath ) ;
break ;
case DISK_COMMAND_CAT_SHORT :
readVolume ( nArg , aArg , & iArg ) ;
ProDOS_CatalogShort ( gpPath ) ;
break ;
// prodos <DSK> cp file1 [file2 ...] /
case DISK_COMMAND_FILE_ADD :
{
# if DEBUG_MAIN
printf ( " DEBUG: cp \n " ) ;
# endif
readVolume ( nArg , aArg , & iArg ) ;
// Check for at least 1 destination (path)
int iDst = nArg - 1 ;
gpPath = getVirtualPath ( nArg , aArg , & iDst , false ) ;
// Check for at least 1 source
bool bFilesAdded = false ;
prodos_InitFileHeader ( & gEntry ) ;
setTimeNow ( & gEntry ) ;
# if DEBUG_MAIN
printf ( " DEBUG: zero'd file entry \n " ) ;
printf ( " iArg: %d \n " , iArg ) ;
printf ( " nArg: %d \n " , nArg ) ;
# endif
if ( iArg = = nArg )
{
printf ( " ERROR: Need virtual destination path. e.g. / \n " ) ;
break ;
}
else
for ( ; iArg < nArg - 1 ; iArg + + )
{
const char * pArg = & aArg [ iArg ] [ 0 ] ;
# if DEBUG_MAIN
printf ( " DEBUG: %s \n " , pArg ) ;
# endif
if ( pArg [ 0 ] = = ' - ' )
bFilesAdded = getCopyConfig ( & gEntry , pArg + 1 ) ;
else
{
bFilesAdded = doCopy ( & gEntry , pArg ) ;
prodos_InitFileHeader ( & gEntry ) ; // prep for next file
setTimeNow ( & gEntry ) ;
}
2017-11-07 15:48:58 +00:00
2017-11-06 05:55:01 +00:00
if ( ! bFilesAdded )
break ;
}
if ( bFilesAdded )
DskSave ( ) ;
break ;
}
case DISK_COMMAND_FILE_DELETE :
2017-12-11 16:25:14 +00:00
{
2017-11-06 05:55:01 +00:00
readVolume ( nArg , aArg , & iArg ) ;
2017-11-07 15:43:37 +00:00
// ProDOS_FileDelete( gpPath ); // pathname_filename
2017-11-06 05:55:01 +00:00
break ;
2017-12-11 16:25:14 +00:00
}
2017-11-06 05:55:01 +00:00
case DISK_COMMAND_FILE_GET :
2017-12-11 16:25:29 +00:00
{
2017-12-29 17:26:51 +00:00
# if DEBUG_MAIN
printf ( " DEBUG: get \n " ) ;
# endif
2017-12-11 16:25:29 +00:00
const char * pBootSectorFileName = NULL ;
for ( ; iArg < nArg ; iArg + + )
{
const char * pArg = & aArg [ iArg ] [ 0 ] ;
if ( pArg [ 0 ] = = ' - ' )
{
if ( strncmp ( pArg + 1 , " boot= " , 5 ) = = 0 )
{
pBootSectorFileName = pArg + 6 ;
size_t nBootSectorNameLength = strlen ( pBootSectorFileName ) ;
if ( ! nBootSectorNameLength )
{
printf ( " ERROR: Need a file name to extract the boot sector to. \n " ) ;
return 1 ;
}
}
else
return printf ( " ERROR: Unknown option: %s \n " , pArg ) ;
}
2017-12-29 17:27:03 +00:00
else
break ;
2017-12-11 16:25:29 +00:00
}
2017-11-06 05:55:01 +00:00
readVolume ( nArg , aArg , & iArg ) ;
2017-12-29 17:26:51 +00:00
# if DEBUG_MAIN
printf ( " DEBUG: get path: %s \n " , gpPath ) ;
# endif
2017-12-11 16:25:29 +00:00
if ( pBootSectorFileName )
ProDOS_ExtractBootSector ( pBootSectorFileName ) ;
else
ProDOS_FileExtract ( gpPath ) ; // pathname_filename
break ;
}
2023-06-13 06:23:47 +00:00
2017-11-06 05:55:01 +00:00
case DISK_COMMAND_VOL_INIT :
2023-06-13 06:23:47 +00:00
{
2017-11-06 05:55:01 +00:00
gnDskSize = DSK_SIZE_312 ; // TODO: --size=140 --size=800 --size=32
if ( ! DskGetInterleave ( gpDskName ) )
errorBadInterleave ( ) ;
# if DEBUG_MAIN
printf ( " iArg: %d / %d \n " , iArg , nArg ) ;
# endif
2023-06-13 06:23:47 +00:00
const char * pBootSectorFileName = NULL ;
2017-11-06 05:55:01 +00:00
for ( ; iArg < nArg ; iArg + + )
{
const char * pArg = & aArg [ iArg ] [ 0 ] ;
# if DEBUG_MAIN
printf ( " #%d: %s \n " , iArg , pArg ) ;
# endif
if ( pArg [ 0 ] = = ' - ' )
{
2023-06-13 06:23:47 +00:00
if ( strncmp ( pArg + 1 , " boot= " , 5 ) = = 0 )
{
if ( pBootSectorFileName )
printf ( " ERROR: Already have boot sector filename. Skipping. \n " ) ;
else
pBootSectorFileName = pArg + 6 ;
}
else
2017-11-06 05:55:01 +00:00
if ( strncmp ( pArg + 1 , " size= " , 5 ) = = 0 )
{
int size = atoi ( pArg + 6 ) ;
if ( size = = 140 ) gnDskSize = DSK_SIZE_514 ;
if ( size = = 800 ) gnDskSize = DSK_SIZE_312 ;
if ( size = = 32 ) gnDskSize = DSK_SIZE_32M ;
# if DEBUG_MAIN
printf ( " INIT: size = %s \n " , itoa_comma ( gnDskSize ) ) ;
# endif
2017-11-07 15:48:58 +00:00
}
2017-11-06 05:55:01 +00:00
else
return printf ( " ERROR: Unknown option: %s \n " , pArg ) ;
}
else
break ;
}
gpPath = getVirtualPath ( nArg , aArg , & iArg , false ) ;
# if DEBUG_MAIN
printf ( " INIT: path: %s \n " , gpPath ) ;
printf ( " iArg: %d / %d \n " , iArg , nArg ) ;
# endif
if ( gpPath )
{
ProDOS_Init ( gpPath ) ;
2023-06-13 06:23:47 +00:00
if ( pBootSectorFileName )
{
bool bReplaced = ProDOS_ReplaceBootSector ( pBootSectorFileName ) ;
if ( ! bReplaced )
printf ( " ERROR: Couldn't replace boot sector \n " ) ;
}
2017-11-06 05:55:01 +00:00
DskSave ( ) ;
}
else
return printf ( " ERROR: Need virtual volume name. e.g. /TEST \n " ) ;
break ;
2023-06-13 06:23:47 +00:00
}
2017-11-06 05:55:01 +00:00
default :
2023-04-07 02:15:11 +00:00
if ( ( nArg < 2 ) | | ! pCommand )
2017-11-06 18:00:10 +00:00
return usage ( ) ;
else
return printf ( " ERROR: Unknown command: %s \n " , pCommand ) ;
2017-11-06 05:55:01 +00:00
break ;
}
return 0 ;
}