home *** CD-ROM | disk | FTP | other *** search
/ Collection of Hack-Phreak Scene Programs / cleanhpvac.zip / cleanhpvac / HPACK78S.ZIP / arc.c < prev    next >
C/C++ Source or Header  |  1992-11-05  |  19KB  |  649 lines

  1. /****************************************************************************
  2. *                                                                            *
  3. *                            HPACK Multi-System Archiver                        *
  4. *                            ===========================                        *
  5. *                                                                            *
  6. *                           Archimedes-Specific Routines                        *
  7. *                             ARC.C  Updated 21/09/92                        *
  8. *                                                                            *
  9. * This program is protected by copyright and as such any use or copying of    *
  10. *  this code for your own purposes directly or indirectly is highly uncool    *
  11. *                      and if you do so there will be....trubble.                *
  12. *                 And remember: We know where your kids go to school.            *
  13. *                                                                            *
  14. *            Copyright 1992  P.Gutmann & J.Williams. All rights reserved        *
  15. *                                                                            *
  16. ****************************************************************************/
  17.  
  18. /* The Archimedes makes all system calls via software interrupts (SWI's).
  19.    Some SWI's have 16 different versions of the same call, depending on
  20.    which way the wind is blowing at the time, but with 32-bit registers to
  21.    specify the call type you can probably get away with this.
  22.  
  23.    In addition, Risc-OS handles all data in terms of 32-bit unsigned values.
  24.    This means a lot of the following code is pretty Vaxocentric (well,
  25.    Arcocentric), ie assuming type int = type char * and so on.
  26.  
  27.    "The determined programmer can write BBC Basic V in *any* language"
  28.                                             - Rastaman Ja */
  29.  
  30. #include <ctype.h>
  31. #include <stddef.h>
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <stdarg.h>
  35. #include <string.h>
  36. #include <time.h>
  37. #include "defs.h"
  38. #include "arcdir.h"
  39. #include "flags.h"
  40. #include "frontend.h"
  41. #include "system.h"
  42. #include "wildcard.h"
  43. #include "io/hpackio.h"
  44.  
  45. #include "kernel.h"
  46.  
  47. /* The time difference between the Archimedes and Unix epochs, in seconds */
  48.  
  49. #define ARC_TIME_OFFSET        0x7E059280L
  50.  
  51. /* Function numbers for SWI's (SWI number).  Make these 0x200xx to repress
  52.    errors */
  53.  
  54. #define OS_Byte            0x06
  55. #define OS_File            0x08
  56. #define OS_Args            0x09
  57. #define OS_Find            0x0D
  58. #define OS_GBPB            0x0C        /* The famous heebeegeebee call */
  59. #define OS_FSControl    0x29
  60. #define OS_ReadModeVar    0x35
  61.  
  62. /* Subfunctions for the above (R0 value).  The main thing to watch out for
  63.    is that there are about 20 ways of doing anything.  Some of them are
  64.    interchangeable */
  65.  
  66. #define SET_CATINFO        0x01        /* Set catalogue info (used for SetTime) */
  67. #define SET_LOADADDR    0x02        /* Set load address */
  68. #define SET_EXECADDR    0x03        /* Set execute address */
  69. #define SET_ATTRIBUTE    0x04        /* Set file/dir attribute */
  70. #define GET_CATINFO        0x05        /* Get catalogue info (used for SetTime) */
  71. #define DELETE_FILE        0x06        /* Delete a file/directory */
  72. #define CREATE_DIR        0x08        /* Create a directory */
  73. #define SET_FILETYPE    0x12        /* Set a file's type */
  74.  
  75. #define READ_POINTER    0x00        /* Read current file pointer */
  76. #define WRITE_POINTER    0x01        /* Write current file pointer */
  77. #define READ_EXTENT        0x02        /* Read size of file */
  78. #define WRITE_EXTENT    0x03        /* Write size of file */
  79. #define ENSURE_FILE        0xFF        /* Ensure all data is written to file */
  80.  
  81. #define CLOSE_FILE        0x00        /* Close a file (one of several variants) */
  82. #define CREATE_FILE        0x83        /* Create a file (one of many variants) */
  83. #define OPEN_READ        0x43        /* Open file for read access */
  84. #define OPEN_UPDATE        0xC3        /* Open file for R/W access */
  85.  
  86. #define WRITE_BYTES        0x02        /* Write data (one of several variants) */
  87. #define READ_BYTES        0x04        /* Read data (one of several variants) */
  88. #define READ_DIRINFO    0x0A        /* Read directory info (one of many) */
  89.  
  90. #define RENAME            0x19        /* Rename file/directory */
  91.  
  92. /* Various file types */
  93.  
  94. #define FILETYPE_DATA        0x00000FFDL    /* Generic data file */
  95. #define FILETYPE_ARCHIVE    0x00000DDCL    /* Sparc data file */
  96. #define FILETYPE_DOS        0x00000FE4L    /* MSDOS data file */
  97.  
  98. /* Offsets in the block of data returned by OS_GBPG/READ_DIRINFO */
  99.  
  100. #define INFO_LOADADDR    0
  101. #define INFO_EXECADDR    4
  102. #define INFO_SIZE        8
  103. #define INFO_ATTR        12
  104. #define INFO_OBJTYPE    16
  105. #define INFO_FILENAME    20
  106.  
  107. /* File object types */
  108.  
  109. #define FILEOBJ_FILE    1
  110. #define FILEOBJ_DIR        2
  111.  
  112. /* The routine to call SWI's from C */
  113.  
  114. int SWI( int inRegCount, int outRegCount, int swiCode, ... )
  115.     {
  116.     va_list argPtr;
  117.     _kernel_swi_regs regsIn, regsOut;
  118.     _kernel_oserror *errorInfo;
  119.     int count;
  120.     int *temp;
  121.  
  122.     va_start( argPtr, swiCode );
  123.  
  124.     /* Pull the input registers off the stack */
  125.     for( count = 0; count < inRegCount; count++ )
  126.         regsIn.r[ count ] = va_arg( argPtr, int );
  127.  
  128.     if( ( errorInfo = _kernel_swi( swiCode, ®sIn, ®sOut ) ) != NULL )
  129.         {
  130.         printf( "Argh! SWI error! %s\n", errorInfo->errmess );
  131.         va_end( argPtr );
  132.         return( ERROR );
  133.         }
  134.  
  135.     /* Put the returned values into the output vars */
  136.     for( count = 0; count < outRegCount; count++ )
  137.         {
  138.         temp = va_arg( argPtr, int * );
  139.         if( temp != NULL )
  140.             *temp = regsOut.r[ count ];
  141.         }
  142.  
  143.     va_end( argPtr );
  144.     return( OK );
  145.     }
  146.  
  147. /****************************************************************************
  148. *                                                                            *
  149. *                                HPACKIO Functions                            *
  150. *                                                                            *
  151. ****************************************************************************/
  152.  
  153. /* Create a new file */
  154.  
  155. FD hcreat( const char *fileName, const int attr )
  156.     {
  157.     LONG r0;
  158.  
  159.     if( attr );            /* Get rid of unused parameter warning */
  160.     if( SWI( 2, 1, OS_Find, CREATE_FILE, ( LONG ) fileName, &r0 ) == ERROR )
  161.         return( IO_ERROR );
  162.     else
  163.         return( r0 ? ( FD ) r0 : IO_ERROR );
  164.     }
  165.  
  166. /* Open an existing file.  We have to be careful here since even if the file
  167.    doesn't exist the call will still return a FD of 0, and performing a
  168.    subsequent courtesy close on this FD has the cute side-effect of closing
  169.    *all* open FD's */
  170.  
  171. FD hopen( const char *fileName, const int mode )
  172.     {
  173.     LONG r0;
  174.     int status;
  175.  
  176.     if( mode == O_RDONLY )
  177.         status = SWI( 2, 1, OS_Find, OPEN_READ, fileName, &r0 );
  178.     else
  179.         status = SWI( 2, 1, OS_Find, OPEN_UPDATE, fileName, &r0 );
  180.     return( ( status == ERROR || !r0 ) ? IO_ERROR : ( FD ) r0 );
  181.     }
  182.  
  183. /* Close a file */
  184.  
  185. int hclose( const FD theFD )
  186.     {
  187.     if( SWI( 3, 0, OS_Find, CLOSE_FILE, ( LONG ) theFD, 0L ) == ERROR )
  188.         return( IO_ERROR );
  189.     else
  190.         return( OK );
  191.     }
  192.  
  193. /* Read data from a file */
  194.  
  195. int hread( const FD theFD, void *buffer, const unsigned int bufSize )
  196.     {
  197.     LONG r0, r1, r2, r3;
  198.  
  199.     if( SWI( 4, 4, OS_GBPB, READ_BYTES, ( LONG ) theFD, buffer, ( LONG ) bufSize, \
  200.              &r0, &r1, &r2, &r3 ) == ERROR )
  201.         return( IO_ERROR );
  202.     else
  203.         return( ( int ) ( bufSize - r3 ) );
  204.     }
  205.  
  206. /* Write data to a file */
  207.  
  208. int hwrite( const FD theFD, void *buffer, const unsigned int bufSize )
  209.     {
  210.     LONG r0, r1, r2;
  211.  
  212.     if( SWI( 4, 3, OS_GBPB, WRITE_BYTES, ( LONG ) theFD, buffer, ( LONG ) bufSize, \
  213.              &r0, &r1, &r2 ) == ERROR )
  214.         return( 0 );
  215.     else
  216.         return( ( int ) ( r2 - ( LONG ) buffer ) );
  217.     }
  218.  
  219. /* Seek to a position in a file.  The Arc can only do an absolute seek so
  220.    we need to figure out where to move the pointer ourselves */
  221.  
  222. long hlseek( const FD theFD, const long position, const int whence )
  223.     {
  224.     LONG r0, r1, r2;
  225.  
  226.     if( whence == SEEK_SET )
  227.         /* Just move the pointer to where we want to go */
  228.         SWI( 3, 0, OS_Args, WRITE_POINTER,( LONG ) theFD, position );
  229.     else
  230.         if( whence == SEEK_CUR )
  231.             {
  232.             /* Find out where we are, add the offset, and move there */
  233.             SWI(3, 3, OS_Args, READ_POINTER, ( LONG ) theFD, 0L, &r0, &r1, &r2 );
  234.             SWI(3, 0, OS_Args, WRITE_POINTER, ( LONG ) theFD, r2 + position );
  235.             }
  236.         else
  237.             {
  238.             /* Force all data for the file handle to disk, find out how big
  239.                the file is now, then seek back from there */
  240.             SWI( 2, 0, OS_Args, ENSURE_FILE, ( LONG ) theFD );
  241.             SWI( 2, 3, OS_Args, READ_EXTENT, ( LONG ) theFD, &r0, &r1, &r2 );
  242.             SWI( 3, 0, OS_Args, WRITE_POINTER, ( LONG ) theFD, r2 + position );
  243.             }
  244.  
  245.     if( SWI( 3, 3, OS_Args, READ_POINTER, ( LONG ) theFD, 0L, &r0, &r1, &r2 ) == ERROR )
  246.         return( IO_ERROR );
  247.     else
  248.         return( ( long ) r2 );
  249.     }
  250.  
  251. /* Return the current position in the file */
  252.  
  253. long htell( const FD theFD )
  254.     {
  255.     LONG r0, r1, r2;
  256.  
  257.     if( SWI( 3, 3, OS_Args, READ_POINTER, ( LONG ) theFD, 0L, &r0, &r1, &r2 ) == ERROR )
  258.         return( IO_ERROR );
  259.     else
  260.         return( ( long ) r2 );
  261.     }
  262.  
  263. /* Truncate a file at the current position by finding where we are and then
  264.    setting this as the new extent */
  265.  
  266. int htruncate( const FD theFD )
  267.     {
  268.     LONG r0, r1, r2;
  269.  
  270.     if( SWI( 3, 3, OS_Args, READ_POINTER, ( LONG ) theFD, 0L, &r0, &r1, &r2 ) != ERROR && \
  271.         SWI( 3, 0, OS_Args, WRITE_EXTENT, ( LONG ) theFD, r2 ) != ERROR )
  272.         return( OK );
  273.     else
  274.         return( IO_ERROR );
  275.     }
  276.  
  277. /* Remove a file */
  278.  
  279. int hunlink( const char *fileName )
  280.     {
  281.     if( SWI( 2, 0, OS_File, DELETE_FILE, fileName ) == ERROR )
  282.         return( IO_ERROR );
  283.     else
  284.         return( OK );
  285.     }
  286.  
  287. /* Create a directory */
  288.  
  289. int hmkdir( const char *dirName, const int attr )
  290.     {
  291.     if( attr );            /* Get rid of unused parameter warning */
  292.     if( SWI( 5, 0, OS_File, CREATE_DIR, dirName, 0L, 0L, 0L ) == ERROR )
  293.         return( ERROR );
  294.     else
  295.         return( OK );
  296.     }
  297.  
  298. /* Rename a file */
  299.  
  300. int hrename( const char *srcName, const char *destName )
  301.     {
  302.     if( SWI( 3, 0, OS_FSControl, RENAME, ( LONG ) srcName, ( LONG ) destName ) == ERROR )
  303.         return( ERROR );
  304.     else
  305.         return( OK );
  306.     }
  307.  
  308. /* Set/change a file/dirs attributes */
  309.  
  310. int hchmod( const char *fileName, const WORD attr )
  311.     {
  312.     if( SWI( 6, 0, OS_File, SET_ATTRIBUTE, fileName, 0L, 0L, 0L, ( LONG ) attr ) == ERROR )
  313.         return( ERROR );
  314.     else
  315.         return( OK );
  316.     }
  317.  
  318. /****************************************************************************
  319. *                                                                            *
  320. *                                HPACKLIB Functions                            *
  321. *                                                                            *
  322. ****************************************************************************/
  323.  
  324. /* Get an input character, no echo */
  325.  
  326. int hgetch( void )
  327.     {
  328.     LONG r0, r1, r2 = 255;
  329.  
  330.     while( r2 != 0 )
  331.         SWI( 3, 3, OS_Byte, 129, 0, 100, &r0, &r1, &r2 );
  332.  
  333.     return( ( int ) r1 );
  334.     }
  335.  
  336. /****************************************************************************
  337. *                                                                            *
  338. *                                SYSTEM Functions                            *
  339. *                                                                            *
  340. ****************************************************************************/
  341.  
  342. /* Set file time */
  343.  
  344. void setFileTime( const char *fileName, const LONG time )
  345.     {
  346.     LONG r0, r1, r2, r3, r4, r5;
  347.  
  348.     SWI( 2, 6, OS_File, GET_CATINFO, fileName, &r0, &r1, &r2, &r3, &r4, &r5 );
  349.     r3 = ( time + ARC_TIME_OFFSET ) << 1;
  350.     r4 &= 0x00FFFFFFL;
  351.     if( time & 1L )            /* Add seconds */
  352.         r4 |= 0x10000000L;
  353.     SWI( 6, 0, OS_File, SET_CATINFO, fileName, r2, r3, r4, r5 );
  354.     }
  355.  
  356. /* Set file type */
  357.  
  358. void setFileType( const char *fileName, const WORD type )
  359.     {
  360.     SWI( 3, 0, OS_File, SET_FILETYPE, fileName, ( LONG ) type );
  361.     }
  362.  
  363. /* Set file load, execute address */
  364.  
  365. void setLoadAddress( const char *fileName, const LONG loadAddr )
  366.     {
  367.     SWI( 3, 0, OS_File, SET_LOADADDR, fileName, loadAddr );
  368.     }
  369.  
  370. void setExecAddress( const char *fileName, const LONG execAddr )
  371.     {
  372.     SWI( 4, 0,  OS_File, SET_EXECADDR, fileName, 0L, execAddr );
  373.     }
  374.  
  375. /* Find the first/next file in a directory.  Since Risc-OS doesn't keep
  376.    track of where we are via some sort of magic number, we need to do a
  377.    certain amount of work to remember the path and filespec we're processing.
  378.    In addition there is a bug in the heebeegeebee routines in that only a
  379.    fileSpec of '*' will work, so we need to keep track of the true fileSpec
  380.    and perform the matching ourselves.  Finally, in order to improve
  381.    performance we need to buffer multiple entries in memory, and handle
  382.    access to variable-length records aligned to longword boundaries.  Change
  383.    the following code at your own risk! */
  384.  
  385. typedef struct {
  386.                LONG loadAddr;        /* Program load address */
  387.                LONG execAddr;        /* Program execute address */
  388.                LONG length;            /* File length */
  389.                LONG attr;            /* File attributes */
  390.                LONG objType;        /* File object type */
  391.                BYTE name[ 1 ];        /* File name */
  392.                } ARC_FILEINFO;
  393.  
  394. BOOLEAN findFirst( const char *filePath, const ATTR fileAttr, FILEINFO *fileInfo )
  395.     {
  396.     char *fileNamePtr, *pathPtr = fileInfo->dirPath;
  397.     int filePathLen = strlen( filePath );
  398.  
  399.     /* Set up Risc-OS bookkeeping information */
  400.     fileInfo->dirPos = 0L;
  401.     fileInfo->currEntry = DIRBUF_ENTRIES;    /* Force a read */
  402.     fileInfo->matchAttr = fileAttr;
  403.     fileInfo->wantArchive = FALSE;
  404.     strcpy( fileInfo->dirPath, filePath );
  405.  
  406.     /* Now find the last directory seperator */
  407.     for( fileNamePtr = pathPtr + strlen( pathPtr ); \
  408.          fileNamePtr >= pathPtr && *fileNamePtr != SLASH; \
  409.          fileNamePtr-- );
  410.     if( ( fileNamePtr >= pathPtr ) && ( *fileNamePtr == SLASH ) )
  411.         *fileNamePtr = '\0';    /* Truncate to directory path only */
  412.     fileNamePtr++;                /* Fix fencepost error */
  413.     if( hasWildcards( fileNamePtr, strlen( fileNamePtr ) ) )
  414.         /* Let the main code sort it out */
  415.         strcpy( fileInfo->fileSpec, MATCH_ALL );
  416.     else
  417.         /* Need literal match, need to do special check in findNext() */
  418.         strcpy( fileInfo->fileSpec, fileNamePtr );
  419.     if( fileNamePtr == pathPtr )
  420.         *fileInfo->dirPath = '\0';    /* Make sure we don't get fileSpec == dirPath */
  421.  
  422.     /* If we're looking for an HPACK archive, indicate that we need to
  423.        perform a special match since we can't check for the extension */
  424.     if( !strcmp( filePath + filePathLen - 1, MATCH_ARCHIVE ) )
  425.         {
  426.         fileInfo->wantArchive = TRUE;
  427.         fileInfo->dirPathLen = filePathLen - 1;
  428.         strcpy( fileInfo->fileSpec, MATCH_ALL );
  429.         }
  430.  
  431.     return( findNext( fileInfo ) );
  432.     }
  433.  
  434. BOOLEAN findNext( FILEINFO *fileInfo )
  435.     {
  436.     LONG r0, r1, r2;
  437.     BOOLEAN doContinue = TRUE, hasType = TRUE;
  438.     BYTE idBuffer[ HPACK_ID_SIZE ];
  439.     ARC_FILEINFO *arcInfo;
  440.     FD archiveFileFD;
  441.  
  442.     /* Try and read the directory information */
  443.     do
  444.         {
  445.         /* Read in a bufferful of info if need be */
  446.         if( fileInfo->currEntry == DIRBUF_ENTRIES )
  447.             {
  448.             SWI( 7, 5, OS_GBPB, READ_DIRINFO, \
  449.                  fileInfo->dirPath, fileInfo->dirBuffer, DIRBUF_ENTRIES, \
  450.                         fileInfo->dirPos, DIRINFO_SIZE * DIRBUF_ENTRIES, "*", \
  451.                  &r0, &r1, &r2, &fileInfo->totalEntries, &fileInfo->dirPos );
  452.             fileInfo->currEntry = 0;    /* Reset buffer index */
  453.             fileInfo->nextRecordPtr = ( void * ) fileInfo->dirBuffer;
  454.             }
  455.  
  456.         if( ( fileInfo->totalEntries == 0 ) && ( fileInfo->dirPos < 0 ) )
  457.             /* Check for exactly 0 entries read */
  458.             return( FALSE );
  459.  
  460.         /* Move to the current record and set up a pointer to the next record */
  461.         arcInfo = ( ARC_FILEINFO * ) fileInfo->nextRecordPtr;
  462.         fileInfo->nextRecordPtr = ( char * ) arcInfo->name + strlen( ( char * ) arcInfo->name ) + 1;
  463.         fileInfo->nextRecordPtr = ( char * ) ( ( ( int ) fileInfo->nextRecordPtr + 3 ) & ~3 );
  464.  
  465.         /* Extract the file's type */
  466.         if( ( arcInfo->loadAddr & 0xFFF00000L ) == 0xFFF00000L )
  467.             fileInfo->type = ( WORD ) ( arcInfo->loadAddr >> 8 ) & 0x0FFF;
  468.         else
  469.             {
  470.             fileInfo->type = ( WORD ) FILETYPE_DATA;
  471.             hasType = FALSE;
  472.             }
  473.         fileInfo->isDirectory = arcInfo->objType == FILEOBJ_DIR;
  474.  
  475.         /* If we're specifically looking for an archive file, make sure we
  476.            only match archives.  Specifically we look for files of type
  477.            ARCHIVE or DATA, and untyped files, which aren't directories */
  478.         if( fileInfo->wantArchive )
  479.             {
  480.             if( !fileInfo->isDirectory && \
  481.                 ( ( fileInfo->type == FILETYPE_ARCHIVE ) || \
  482.                   ( fileInfo->type == FILETYPE_DATA ) || \
  483.                   ( fileInfo->type == FILETYPE_DOS ) )
  484.                 {
  485.                 /* Try and open the file to look for the HPACK ID */
  486.                 if( *fileInfo->dirPath )
  487.                     {
  488.                     /* Append a SLASH and the filename */
  489.                     fileInfo->dirPath[ fileInfo->dirPathLen ] = SLASH;
  490.                     strcpy( fileInfo->dirPath + fileInfo->dirPathLen + 1, \
  491.                             ( char * ) arcInfo->name );
  492.                     }
  493.                 else
  494.                     strcpy( fileInfo->dirPath, ( char * ) arcInfo->name );
  495.                 if( ( archiveFileFD = hopen( fileInfo->dirPath, O_RDONLY ) ) != ERROR )
  496.                     {
  497.                     /* Check for the HPACK ID bytes at the start of the archive */
  498.                     if( ( hread( archiveFileFD, idBuffer, HPACK_ID_SIZE ) == HPACK_ID_SIZE ) && \
  499.                         ( !memcmp( idBuffer, "HPAK", 4 ) ) )
  500.                         doContinue = FALSE;
  501.                     hclose( archiveFileFD );
  502.                     }
  503.                 fileInfo->dirPath[ fileInfo->dirPathLen ] = '\0';
  504.                 }
  505.             }
  506.         else
  507.             {
  508.             /* Check whether we've found a directory */
  509.             if( fileInfo->isDirectory )
  510.                 {
  511.                 /* If we want directories, indicate a match */
  512.                 if( fileInfo->matchAttr == ALLFILES_DIRS )
  513.                     doContinue = FALSE;
  514.                 }
  515.             else
  516.                 /* We've found a file, assume a match unless told otherwise */
  517.                 doContinue = FALSE;
  518.  
  519.             /* Check for a literal match if we want one */
  520.             if( !doContinue && strcmp( fileInfo->fileSpec, MATCH_ALL ) )
  521.                 doContinue = stricmp( fileInfo->fileSpec, ( char * ) arcInfo->name );
  522.             }
  523.  
  524.         /* Move to next entry in buffer */
  525.         fileInfo->currEntry++;
  526.         if( fileInfo->currEntry >= fileInfo->totalEntries && fileInfo->dirPos < 0 )
  527.             if( !doContinue )
  528.                 /* We've matched the last entry in the buffer, make sure we
  529.                    exit the next time around */
  530.                 fileInfo->totalEntries = 0;
  531.             else
  532.                 /* Out of entries and no more to read, return */
  533.                 return( FALSE );
  534.         }
  535.     while( doContinue );
  536.  
  537.     /* Copy the information into the fileInfo struct */
  538.     if( hasType )
  539.         {
  540. /*        fileInfo->fTime = ( arcInfo->execAddr << 1 ) - ARC_TIME_OFFSET;*/
  541.         fileInfo->fTime = arcInfo->execAddr + 0x26B0B00L;
  542.         fileInfo->loadAddr = fileInfo->execAddr = ERROR;
  543.         }
  544.     else
  545.         {
  546.         fileInfo->type = ERROR;
  547.         fileInfo->fTime = time( NULL );        /* Fake it with current time */
  548.         fileInfo->loadAddr = arcInfo->loadAddr;
  549.         fileInfo->execAddr = arcInfo->execAddr;
  550.         }
  551.     fileInfo->fSize = arcInfo->length;
  552.     fileInfo->fAttr = ( WORD ) arcInfo->attr;
  553.     strcpy( fileInfo->fName, ( char * ) arcInfo->name );
  554.  
  555.     return( TRUE );
  556.     }
  557.  
  558. /* Set extra info for the archive */
  559.  
  560. void setExtraInfo( const char *archivePath )
  561.     {
  562.     setFileType( archivePath, ( WORD ) FILETYPE_ARCHIVE );
  563.     }
  564.  
  565. /* Case-insensitive string comparisons */
  566.  
  567. int strnicmp( const char *src, const char *dest, int length )
  568.     {
  569.     char srcCh, destCh;
  570.     char *srcPtr = (char *) src, *destPtr = (char *) dest;
  571.  
  572.     while( length-- )
  573.         {
  574.  
  575.         /* Need to be careful with toupper() side-effects */
  576.         srcCh = *srcPtr++;
  577.         srcCh = toupper( srcCh );
  578.         destCh = *destPtr++;
  579.         destCh = toupper( destCh );
  580.  
  581.         if( srcCh != destCh )
  582.             return( srcCh - destCh );
  583.         }
  584.  
  585.     return( 0 );
  586.     }
  587.  
  588. int stricmp( const char *src, const char *dest )
  589.     {
  590.     char srcCh, destCh;
  591.     char *srcPtr = (char *) src, *destPtr = (char *) dest;
  592.  
  593.     while( *srcPtr && *dest )
  594.         {
  595.         /* Need to be careful with toupper() side-effects */
  596.         srcCh = *srcPtr++;
  597.         srcCh = toupper( srcCh );
  598.         destCh = *destPtr++;
  599.         destCh = toupper( destCh );
  600.  
  601.         if( srcCh != destCh )
  602.             return( srcCh - destCh );
  603.         }
  604.  
  605.     return( 0 );
  606.     }
  607.  
  608. /* Lowercase a string */
  609.  
  610. void strlwr( char *string )
  611.     {
  612.     while( *string )
  613.         {
  614.         *string = tolower( *string );
  615.         string++;
  616.         }
  617.     }
  618.  
  619. static int bbcModeVar( int varNo )
  620.     {
  621.     LONG r0, r1, r2;
  622.  
  623.     SWI( 3, 3, OS_ReadModeVar, -1, ( LONG ) varNo, 0, &r0, &r1, &r2 );
  624.     return( ( int ) r2 );
  625.     }
  626.  
  627. void getScreenSize( void )
  628.     {
  629.     screenWidth  = bbcModeVar( 1 ) - 1;
  630.     screenHeight = bbcModeVar( 2 ) - 1;
  631.     }
  632.  
  633. /* "Well we can do this under Risc-OS 3...." */
  634.  
  635. int getCountry( void )
  636.     {
  637.     return( 1 );        /* Default to UK */
  638.     }
  639.  
  640. /* Write out a single char.  Used to fix stdio's GSTrans-ing of
  641.    control characters */
  642.  
  643. void hputchar( const int ch )
  644.     {
  645.     if( ch == '\n' )
  646.         SWI( 0, 0, 256 + '\r' );
  647.     SWI( 0, 0, 256 + ch );
  648.     }
  649.