home *** CD-ROM | disk | FTP | other *** search
- /****************************************************************************
- * *
- * HPACK Multi-System Archiver *
- * =========================== *
- * *
- * Archimedes-Specific Routines *
- * ARC.C Updated 21/09/92 *
- * *
- * This program is protected by copyright and as such any use or copying of *
- * this code for your own purposes directly or indirectly is highly uncool *
- * and if you do so there will be....trubble. *
- * And remember: We know where your kids go to school. *
- * *
- * Copyright 1992 P.Gutmann & J.Williams. All rights reserved *
- * *
- ****************************************************************************/
-
- /* The Archimedes makes all system calls via software interrupts (SWI's).
- Some SWI's have 16 different versions of the same call, depending on
- which way the wind is blowing at the time, but with 32-bit registers to
- specify the call type you can probably get away with this.
-
- In addition, Risc-OS handles all data in terms of 32-bit unsigned values.
- This means a lot of the following code is pretty Vaxocentric (well,
- Arcocentric), ie assuming type int = type char * and so on.
-
- "The determined programmer can write BBC Basic V in *any* language"
- - Rastaman Ja */
-
- #include <ctype.h>
- #include <stddef.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <stdarg.h>
- #include <string.h>
- #include <time.h>
- #include "defs.h"
- #include "arcdir.h"
- #include "flags.h"
- #include "frontend.h"
- #include "system.h"
- #include "wildcard.h"
- #include "io/hpackio.h"
-
- #include "kernel.h"
-
- /* The time difference between the Archimedes and Unix epochs, in seconds */
-
- #define ARC_TIME_OFFSET 0x7E059280L
-
- /* Function numbers for SWI's (SWI number). Make these 0x200xx to repress
- errors */
-
- #define OS_Byte 0x06
- #define OS_File 0x08
- #define OS_Args 0x09
- #define OS_Find 0x0D
- #define OS_GBPB 0x0C /* The famous heebeegeebee call */
- #define OS_FSControl 0x29
- #define OS_ReadModeVar 0x35
-
- /* Subfunctions for the above (R0 value). The main thing to watch out for
- is that there are about 20 ways of doing anything. Some of them are
- interchangeable */
-
- #define SET_CATINFO 0x01 /* Set catalogue info (used for SetTime) */
- #define SET_LOADADDR 0x02 /* Set load address */
- #define SET_EXECADDR 0x03 /* Set execute address */
- #define SET_ATTRIBUTE 0x04 /* Set file/dir attribute */
- #define GET_CATINFO 0x05 /* Get catalogue info (used for SetTime) */
- #define DELETE_FILE 0x06 /* Delete a file/directory */
- #define CREATE_DIR 0x08 /* Create a directory */
- #define SET_FILETYPE 0x12 /* Set a file's type */
-
- #define READ_POINTER 0x00 /* Read current file pointer */
- #define WRITE_POINTER 0x01 /* Write current file pointer */
- #define READ_EXTENT 0x02 /* Read size of file */
- #define WRITE_EXTENT 0x03 /* Write size of file */
- #define ENSURE_FILE 0xFF /* Ensure all data is written to file */
-
- #define CLOSE_FILE 0x00 /* Close a file (one of several variants) */
- #define CREATE_FILE 0x83 /* Create a file (one of many variants) */
- #define OPEN_READ 0x43 /* Open file for read access */
- #define OPEN_UPDATE 0xC3 /* Open file for R/W access */
-
- #define WRITE_BYTES 0x02 /* Write data (one of several variants) */
- #define READ_BYTES 0x04 /* Read data (one of several variants) */
- #define READ_DIRINFO 0x0A /* Read directory info (one of many) */
-
- #define RENAME 0x19 /* Rename file/directory */
-
- /* Various file types */
-
- #define FILETYPE_DATA 0x00000FFDL /* Generic data file */
- #define FILETYPE_ARCHIVE 0x00000DDCL /* Sparc data file */
- #define FILETYPE_DOS 0x00000FE4L /* MSDOS data file */
-
- /* Offsets in the block of data returned by OS_GBPG/READ_DIRINFO */
-
- #define INFO_LOADADDR 0
- #define INFO_EXECADDR 4
- #define INFO_SIZE 8
- #define INFO_ATTR 12
- #define INFO_OBJTYPE 16
- #define INFO_FILENAME 20
-
- /* File object types */
-
- #define FILEOBJ_FILE 1
- #define FILEOBJ_DIR 2
-
- /* The routine to call SWI's from C */
-
- int SWI( int inRegCount, int outRegCount, int swiCode, ... )
- {
- va_list argPtr;
- _kernel_swi_regs regsIn, regsOut;
- _kernel_oserror *errorInfo;
- int count;
- int *temp;
-
- va_start( argPtr, swiCode );
-
- /* Pull the input registers off the stack */
- for( count = 0; count < inRegCount; count++ )
- regsIn.r[ count ] = va_arg( argPtr, int );
-
- if( ( errorInfo = _kernel_swi( swiCode, ®sIn, ®sOut ) ) != NULL )
- {
- printf( "Argh! SWI error! %s\n", errorInfo->errmess );
- va_end( argPtr );
- return( ERROR );
- }
-
- /* Put the returned values into the output vars */
- for( count = 0; count < outRegCount; count++ )
- {
- temp = va_arg( argPtr, int * );
- if( temp != NULL )
- *temp = regsOut.r[ count ];
- }
-
- va_end( argPtr );
- return( OK );
- }
-
- /****************************************************************************
- * *
- * HPACKIO Functions *
- * *
- ****************************************************************************/
-
- /* Create a new file */
-
- FD hcreat( const char *fileName, const int attr )
- {
- LONG r0;
-
- if( attr ); /* Get rid of unused parameter warning */
- if( SWI( 2, 1, OS_Find, CREATE_FILE, ( LONG ) fileName, &r0 ) == ERROR )
- return( IO_ERROR );
- else
- return( r0 ? ( FD ) r0 : IO_ERROR );
- }
-
- /* Open an existing file. We have to be careful here since even if the file
- doesn't exist the call will still return a FD of 0, and performing a
- subsequent courtesy close on this FD has the cute side-effect of closing
- *all* open FD's */
-
- FD hopen( const char *fileName, const int mode )
- {
- LONG r0;
- int status;
-
- if( mode == O_RDONLY )
- status = SWI( 2, 1, OS_Find, OPEN_READ, fileName, &r0 );
- else
- status = SWI( 2, 1, OS_Find, OPEN_UPDATE, fileName, &r0 );
- return( ( status == ERROR || !r0 ) ? IO_ERROR : ( FD ) r0 );
- }
-
- /* Close a file */
-
- int hclose( const FD theFD )
- {
- if( SWI( 3, 0, OS_Find, CLOSE_FILE, ( LONG ) theFD, 0L ) == ERROR )
- return( IO_ERROR );
- else
- return( OK );
- }
-
- /* Read data from a file */
-
- int hread( const FD theFD, void *buffer, const unsigned int bufSize )
- {
- LONG r0, r1, r2, r3;
-
- if( SWI( 4, 4, OS_GBPB, READ_BYTES, ( LONG ) theFD, buffer, ( LONG ) bufSize, \
- &r0, &r1, &r2, &r3 ) == ERROR )
- return( IO_ERROR );
- else
- return( ( int ) ( bufSize - r3 ) );
- }
-
- /* Write data to a file */
-
- int hwrite( const FD theFD, void *buffer, const unsigned int bufSize )
- {
- LONG r0, r1, r2;
-
- if( SWI( 4, 3, OS_GBPB, WRITE_BYTES, ( LONG ) theFD, buffer, ( LONG ) bufSize, \
- &r0, &r1, &r2 ) == ERROR )
- return( 0 );
- else
- return( ( int ) ( r2 - ( LONG ) buffer ) );
- }
-
- /* Seek to a position in a file. The Arc can only do an absolute seek so
- we need to figure out where to move the pointer ourselves */
-
- long hlseek( const FD theFD, const long position, const int whence )
- {
- LONG r0, r1, r2;
-
- if( whence == SEEK_SET )
- /* Just move the pointer to where we want to go */
- SWI( 3, 0, OS_Args, WRITE_POINTER,( LONG ) theFD, position );
- else
- if( whence == SEEK_CUR )
- {
- /* Find out where we are, add the offset, and move there */
- SWI(3, 3, OS_Args, READ_POINTER, ( LONG ) theFD, 0L, &r0, &r1, &r2 );
- SWI(3, 0, OS_Args, WRITE_POINTER, ( LONG ) theFD, r2 + position );
- }
- else
- {
- /* Force all data for the file handle to disk, find out how big
- the file is now, then seek back from there */
- SWI( 2, 0, OS_Args, ENSURE_FILE, ( LONG ) theFD );
- SWI( 2, 3, OS_Args, READ_EXTENT, ( LONG ) theFD, &r0, &r1, &r2 );
- SWI( 3, 0, OS_Args, WRITE_POINTER, ( LONG ) theFD, r2 + position );
- }
-
- if( SWI( 3, 3, OS_Args, READ_POINTER, ( LONG ) theFD, 0L, &r0, &r1, &r2 ) == ERROR )
- return( IO_ERROR );
- else
- return( ( long ) r2 );
- }
-
- /* Return the current position in the file */
-
- long htell( const FD theFD )
- {
- LONG r0, r1, r2;
-
- if( SWI( 3, 3, OS_Args, READ_POINTER, ( LONG ) theFD, 0L, &r0, &r1, &r2 ) == ERROR )
- return( IO_ERROR );
- else
- return( ( long ) r2 );
- }
-
- /* Truncate a file at the current position by finding where we are and then
- setting this as the new extent */
-
- int htruncate( const FD theFD )
- {
- LONG r0, r1, r2;
-
- if( SWI( 3, 3, OS_Args, READ_POINTER, ( LONG ) theFD, 0L, &r0, &r1, &r2 ) != ERROR && \
- SWI( 3, 0, OS_Args, WRITE_EXTENT, ( LONG ) theFD, r2 ) != ERROR )
- return( OK );
- else
- return( IO_ERROR );
- }
-
- /* Remove a file */
-
- int hunlink( const char *fileName )
- {
- if( SWI( 2, 0, OS_File, DELETE_FILE, fileName ) == ERROR )
- return( IO_ERROR );
- else
- return( OK );
- }
-
- /* Create a directory */
-
- int hmkdir( const char *dirName, const int attr )
- {
- if( attr ); /* Get rid of unused parameter warning */
- if( SWI( 5, 0, OS_File, CREATE_DIR, dirName, 0L, 0L, 0L ) == ERROR )
- return( ERROR );
- else
- return( OK );
- }
-
- /* Rename a file */
-
- int hrename( const char *srcName, const char *destName )
- {
- if( SWI( 3, 0, OS_FSControl, RENAME, ( LONG ) srcName, ( LONG ) destName ) == ERROR )
- return( ERROR );
- else
- return( OK );
- }
-
- /* Set/change a file/dirs attributes */
-
- int hchmod( const char *fileName, const WORD attr )
- {
- if( SWI( 6, 0, OS_File, SET_ATTRIBUTE, fileName, 0L, 0L, 0L, ( LONG ) attr ) == ERROR )
- return( ERROR );
- else
- return( OK );
- }
-
- /****************************************************************************
- * *
- * HPACKLIB Functions *
- * *
- ****************************************************************************/
-
- /* Get an input character, no echo */
-
- int hgetch( void )
- {
- LONG r0, r1, r2 = 255;
-
- while( r2 != 0 )
- SWI( 3, 3, OS_Byte, 129, 0, 100, &r0, &r1, &r2 );
-
- return( ( int ) r1 );
- }
-
- /****************************************************************************
- * *
- * SYSTEM Functions *
- * *
- ****************************************************************************/
-
- /* Set file time */
-
- void setFileTime( const char *fileName, const LONG time )
- {
- LONG r0, r1, r2, r3, r4, r5;
-
- SWI( 2, 6, OS_File, GET_CATINFO, fileName, &r0, &r1, &r2, &r3, &r4, &r5 );
- r3 = ( time + ARC_TIME_OFFSET ) << 1;
- r4 &= 0x00FFFFFFL;
- if( time & 1L ) /* Add seconds */
- r4 |= 0x10000000L;
- SWI( 6, 0, OS_File, SET_CATINFO, fileName, r2, r3, r4, r5 );
- }
-
- /* Set file type */
-
- void setFileType( const char *fileName, const WORD type )
- {
- SWI( 3, 0, OS_File, SET_FILETYPE, fileName, ( LONG ) type );
- }
-
- /* Set file load, execute address */
-
- void setLoadAddress( const char *fileName, const LONG loadAddr )
- {
- SWI( 3, 0, OS_File, SET_LOADADDR, fileName, loadAddr );
- }
-
- void setExecAddress( const char *fileName, const LONG execAddr )
- {
- SWI( 4, 0, OS_File, SET_EXECADDR, fileName, 0L, execAddr );
- }
-
- /* Find the first/next file in a directory. Since Risc-OS doesn't keep
- track of where we are via some sort of magic number, we need to do a
- certain amount of work to remember the path and filespec we're processing.
- In addition there is a bug in the heebeegeebee routines in that only a
- fileSpec of '*' will work, so we need to keep track of the true fileSpec
- and perform the matching ourselves. Finally, in order to improve
- performance we need to buffer multiple entries in memory, and handle
- access to variable-length records aligned to longword boundaries. Change
- the following code at your own risk! */
-
- typedef struct {
- LONG loadAddr; /* Program load address */
- LONG execAddr; /* Program execute address */
- LONG length; /* File length */
- LONG attr; /* File attributes */
- LONG objType; /* File object type */
- BYTE name[ 1 ]; /* File name */
- } ARC_FILEINFO;
-
- BOOLEAN findFirst( const char *filePath, const ATTR fileAttr, FILEINFO *fileInfo )
- {
- char *fileNamePtr, *pathPtr = fileInfo->dirPath;
- int filePathLen = strlen( filePath );
-
- /* Set up Risc-OS bookkeeping information */
- fileInfo->dirPos = 0L;
- fileInfo->currEntry = DIRBUF_ENTRIES; /* Force a read */
- fileInfo->matchAttr = fileAttr;
- fileInfo->wantArchive = FALSE;
- strcpy( fileInfo->dirPath, filePath );
-
- /* Now find the last directory seperator */
- for( fileNamePtr = pathPtr + strlen( pathPtr ); \
- fileNamePtr >= pathPtr && *fileNamePtr != SLASH; \
- fileNamePtr-- );
- if( ( fileNamePtr >= pathPtr ) && ( *fileNamePtr == SLASH ) )
- *fileNamePtr = '\0'; /* Truncate to directory path only */
- fileNamePtr++; /* Fix fencepost error */
- if( hasWildcards( fileNamePtr, strlen( fileNamePtr ) ) )
- /* Let the main code sort it out */
- strcpy( fileInfo->fileSpec, MATCH_ALL );
- else
- /* Need literal match, need to do special check in findNext() */
- strcpy( fileInfo->fileSpec, fileNamePtr );
- if( fileNamePtr == pathPtr )
- *fileInfo->dirPath = '\0'; /* Make sure we don't get fileSpec == dirPath */
-
- /* If we're looking for an HPACK archive, indicate that we need to
- perform a special match since we can't check for the extension */
- if( !strcmp( filePath + filePathLen - 1, MATCH_ARCHIVE ) )
- {
- fileInfo->wantArchive = TRUE;
- fileInfo->dirPathLen = filePathLen - 1;
- strcpy( fileInfo->fileSpec, MATCH_ALL );
- }
-
- return( findNext( fileInfo ) );
- }
-
- BOOLEAN findNext( FILEINFO *fileInfo )
- {
- LONG r0, r1, r2;
- BOOLEAN doContinue = TRUE, hasType = TRUE;
- BYTE idBuffer[ HPACK_ID_SIZE ];
- ARC_FILEINFO *arcInfo;
- FD archiveFileFD;
-
- /* Try and read the directory information */
- do
- {
- /* Read in a bufferful of info if need be */
- if( fileInfo->currEntry == DIRBUF_ENTRIES )
- {
- SWI( 7, 5, OS_GBPB, READ_DIRINFO, \
- fileInfo->dirPath, fileInfo->dirBuffer, DIRBUF_ENTRIES, \
- fileInfo->dirPos, DIRINFO_SIZE * DIRBUF_ENTRIES, "*", \
- &r0, &r1, &r2, &fileInfo->totalEntries, &fileInfo->dirPos );
- fileInfo->currEntry = 0; /* Reset buffer index */
- fileInfo->nextRecordPtr = ( void * ) fileInfo->dirBuffer;
- }
-
- if( ( fileInfo->totalEntries == 0 ) && ( fileInfo->dirPos < 0 ) )
- /* Check for exactly 0 entries read */
- return( FALSE );
-
- /* Move to the current record and set up a pointer to the next record */
- arcInfo = ( ARC_FILEINFO * ) fileInfo->nextRecordPtr;
- fileInfo->nextRecordPtr = ( char * ) arcInfo->name + strlen( ( char * ) arcInfo->name ) + 1;
- fileInfo->nextRecordPtr = ( char * ) ( ( ( int ) fileInfo->nextRecordPtr + 3 ) & ~3 );
-
- /* Extract the file's type */
- if( ( arcInfo->loadAddr & 0xFFF00000L ) == 0xFFF00000L )
- fileInfo->type = ( WORD ) ( arcInfo->loadAddr >> 8 ) & 0x0FFF;
- else
- {
- fileInfo->type = ( WORD ) FILETYPE_DATA;
- hasType = FALSE;
- }
- fileInfo->isDirectory = arcInfo->objType == FILEOBJ_DIR;
-
- /* If we're specifically looking for an archive file, make sure we
- only match archives. Specifically we look for files of type
- ARCHIVE or DATA, and untyped files, which aren't directories */
- if( fileInfo->wantArchive )
- {
- if( !fileInfo->isDirectory && \
- ( ( fileInfo->type == FILETYPE_ARCHIVE ) || \
- ( fileInfo->type == FILETYPE_DATA ) || \
- ( fileInfo->type == FILETYPE_DOS ) )
- {
- /* Try and open the file to look for the HPACK ID */
- if( *fileInfo->dirPath )
- {
- /* Append a SLASH and the filename */
- fileInfo->dirPath[ fileInfo->dirPathLen ] = SLASH;
- strcpy( fileInfo->dirPath + fileInfo->dirPathLen + 1, \
- ( char * ) arcInfo->name );
- }
- else
- strcpy( fileInfo->dirPath, ( char * ) arcInfo->name );
- if( ( archiveFileFD = hopen( fileInfo->dirPath, O_RDONLY ) ) != ERROR )
- {
- /* Check for the HPACK ID bytes at the start of the archive */
- if( ( hread( archiveFileFD, idBuffer, HPACK_ID_SIZE ) == HPACK_ID_SIZE ) && \
- ( !memcmp( idBuffer, "HPAK", 4 ) ) )
- doContinue = FALSE;
- hclose( archiveFileFD );
- }
- fileInfo->dirPath[ fileInfo->dirPathLen ] = '\0';
- }
- }
- else
- {
- /* Check whether we've found a directory */
- if( fileInfo->isDirectory )
- {
- /* If we want directories, indicate a match */
- if( fileInfo->matchAttr == ALLFILES_DIRS )
- doContinue = FALSE;
- }
- else
- /* We've found a file, assume a match unless told otherwise */
- doContinue = FALSE;
-
- /* Check for a literal match if we want one */
- if( !doContinue && strcmp( fileInfo->fileSpec, MATCH_ALL ) )
- doContinue = stricmp( fileInfo->fileSpec, ( char * ) arcInfo->name );
- }
-
- /* Move to next entry in buffer */
- fileInfo->currEntry++;
- if( fileInfo->currEntry >= fileInfo->totalEntries && fileInfo->dirPos < 0 )
- if( !doContinue )
- /* We've matched the last entry in the buffer, make sure we
- exit the next time around */
- fileInfo->totalEntries = 0;
- else
- /* Out of entries and no more to read, return */
- return( FALSE );
- }
- while( doContinue );
-
- /* Copy the information into the fileInfo struct */
- if( hasType )
- {
- /* fileInfo->fTime = ( arcInfo->execAddr << 1 ) - ARC_TIME_OFFSET;*/
- fileInfo->fTime = arcInfo->execAddr + 0x26B0B00L;
- fileInfo->loadAddr = fileInfo->execAddr = ERROR;
- }
- else
- {
- fileInfo->type = ERROR;
- fileInfo->fTime = time( NULL ); /* Fake it with current time */
- fileInfo->loadAddr = arcInfo->loadAddr;
- fileInfo->execAddr = arcInfo->execAddr;
- }
- fileInfo->fSize = arcInfo->length;
- fileInfo->fAttr = ( WORD ) arcInfo->attr;
- strcpy( fileInfo->fName, ( char * ) arcInfo->name );
-
- return( TRUE );
- }
-
- /* Set extra info for the archive */
-
- void setExtraInfo( const char *archivePath )
- {
- setFileType( archivePath, ( WORD ) FILETYPE_ARCHIVE );
- }
-
- /* Case-insensitive string comparisons */
-
- int strnicmp( const char *src, const char *dest, int length )
- {
- char srcCh, destCh;
- char *srcPtr = (char *) src, *destPtr = (char *) dest;
-
- while( length-- )
- {
-
- /* Need to be careful with toupper() side-effects */
- srcCh = *srcPtr++;
- srcCh = toupper( srcCh );
- destCh = *destPtr++;
- destCh = toupper( destCh );
-
- if( srcCh != destCh )
- return( srcCh - destCh );
- }
-
- return( 0 );
- }
-
- int stricmp( const char *src, const char *dest )
- {
- char srcCh, destCh;
- char *srcPtr = (char *) src, *destPtr = (char *) dest;
-
- while( *srcPtr && *dest )
- {
- /* Need to be careful with toupper() side-effects */
- srcCh = *srcPtr++;
- srcCh = toupper( srcCh );
- destCh = *destPtr++;
- destCh = toupper( destCh );
-
- if( srcCh != destCh )
- return( srcCh - destCh );
- }
-
- return( 0 );
- }
-
- /* Lowercase a string */
-
- void strlwr( char *string )
- {
- while( *string )
- {
- *string = tolower( *string );
- string++;
- }
- }
-
- static int bbcModeVar( int varNo )
- {
- LONG r0, r1, r2;
-
- SWI( 3, 3, OS_ReadModeVar, -1, ( LONG ) varNo, 0, &r0, &r1, &r2 );
- return( ( int ) r2 );
- }
-
- void getScreenSize( void )
- {
- screenWidth = bbcModeVar( 1 ) - 1;
- screenHeight = bbcModeVar( 2 ) - 1;
- }
-
- /* "Well we can do this under Risc-OS 3...." */
-
- int getCountry( void )
- {
- return( 1 ); /* Default to UK */
- }
-
- /* Write out a single char. Used to fix stdio's GSTrans-ing of
- control characters */
-
- void hputchar( const int ch )
- {
- if( ch == '\n' )
- SWI( 0, 0, 256 + '\r' );
- SWI( 0, 0, 256 + ch );
- }
-