/*
 * Name   : file.c
 * Desc   : whole/part file handling for manual program
 * Author : James Bye
 * Date   : 15th October 1991
 *
 * History
 * -------
 *
 *  15-Oct-91  JAB  Created this file
 *
 *
 * This source will be part of the manual software code library
 */


/*************************************************
 * Include files                                 *
 *************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "kernel.h" 

#include "file.h"

/*************************************************
 * Static variables                              *
 *************************************************/


static _kernel_oserror  *last_oserror = NULL; /* the last os error */

                                                   

/**********************************************************
 * OS_File calls                                          *
 * -------------                                          *
 *                                                        *
 * These calls call the SWI' as detailed in the RISC OS   *
 * v2.00 PRM                                              *
 *                                                        *
 * They deal mainly with whole files, such as:-           *
 *                                                        *
 *    Loading                                             *
 *    Saving                                              *
 *    Writing catalogue information                       *
 *    Reading catalogue information                       *
 *    etc...                                              *
 *                                                        *
 **********************************************************/


  
/*************************************************
 * Reason codes etc                               *
 *************************************************/

/*-- OS File --*/

#define OS_File    0x08
#define SaveBlock    10
#define ReadCat       5
#define Delete        6
#define CreateFile   11
#define CreateDir     8
#define LoadFile    255


/*
 * Name : file_lasterror
 * Desc : returns the last error encountered by this module
 * In   : None
 * Out  : pointer to error block
 */

extern _kernel_oserror *file_lasterror ( void )
{
  return(last_oserror);
}


/*
 * Name : file_memdump
 * Desc : dumps memory to a file
 * In   : char *filename   - pointer to a filename
 *        int   filetype   - filetype number
 *        char *buffer     - pointer to a buffer
 *        int   size       - size of buffer
 * Out  : pointer to error block
 */

extern _kernel_oserror *file_memdump ( char *filename, int filetype,
                                       char *buffer, int size       )
{
_kernel_swi_regs r;

  r.r[0] = SaveBlock;
  r.r[1] = (int) filename;
  r.r[2] = filetype;
  r.r[4] = (int) buffer;
  r.r[5] = ((int) buffer) + size;
  last_oserror = _kernel_swi(OS_File,&r,&r);
  return(last_oserror);
}

                     

/*
 * Name : file_writecat
 * Desc : a group of functions that deal with catalogue writing
 *        they are prototyped as follows :-
 *
 *    file_writecat1  - writes load address,exec address,attribs to file
 *    file_writecat2  - writes load address only
 *    file_writecat3  - writes execution address only
 *    file_writecat4  - writes attribs only
 *    file_writecat9  - date/time stamp; filetype to data
 *    file_writecat18 - set filetype and stamp
 *
 * In  : int   code- reason code           
 *       char *p   - pathname
 *       int   r2  - register value for R2 - depending on call
 *       int   r3  - register value for R3 - depending on call
 *       int   r5  - register value for R5 - depending on call
 * Out : pointer to error block
 * Info: for call 1  - r2:  load address
 *                     r3:  exec address
 *                     r5:  attribs
 *       for call 2  - r2:  load address
 *       for call 3  - r3:  execution address
 *       for call 4  - r5:  attribs
 *       for call 9  - None
 *       for call 18 - r2:  filetype
 */

#ifndef __writecat_protos
#define file_writecat1(p,load_addr,exec_addr,attribs) file_writecat(1,p,load_addr,exec_addr,attribs)
#define file_writecat2(p,load_addr)                   file_writecat(2,p,load_addr,0,0)
#define file_writecat3(p,exec_addr)                   file_writecat(3,p,0,exec_addr,0)
#define file_writecat4(p,attribs)                     file_writecat(4,p,0,0,attribs)
#define file_writecat9(p)                             file_writecat(9,p,0,0,0)
#define file_writecat18(p,filetype)                   file_writecat(18,p,filetype,0,0)
#endif

extern _kernel_oserror *file_writecat ( int code, char *p, int r2, int r3, int r5 )
{
_kernel_swi_regs  r;

  r.r[0] = code;
  r.r[1] = (int) p;
  r.r[2] = r2;
  r.r[3] = r3;
  r.r[5] = r5;
  last_oserror = _kernel_swi(OS_File,&r,&r);
  return(last_oserror);
}



/*
 * Name : file_readcat
 * Desc : reads catalogue information for a file
 * In   : char *filename   - pointer to a filename
 *        int  *type       - pointer for the type
 *        int  *laddr      - pointer for load address 
 *        int  *eaddr      - pointer for exec address
 *        int  *length     - pointer for length
 *        int  *attrib     - pointer for attributes
 * Out  : returns pointer to error block
 * Info : any of the destination pointer can set to NULL and if so
 *        then they will not be written to
 *        to find the size only, you would call as follows :-
 *         file_readcat(filename,NULL,NULL,NULL,&size,NULL);
 */                                                    

#define IfPtrThenWrite(ptr,d) if(ptr != NULL) *ptr = d

extern _kernel_oserror *file_readcat ( char *filename, int *type, int *laddr, int *eaddr,
                                       int *length, int *attrib )
{
_kernel_swi_regs  r;

  r.r[0] = ReadCat;
  r.r[1] = (int) filename;
  last_oserror = _kernel_swi(OS_File,&r,&r);
  if(last_oserror == NULL)
  {                                
     IfPtrThenWrite(type,r.r[0]);
     IfPtrThenWrite(laddr,r.r[2]);
     IfPtrThenWrite(eaddr,r.r[3]);
     IfPtrThenWrite(length,r.r[4]);
     IfPtrThenWrite(attrib,r.r[5]);
  }
  return(last_oserror);
}
           


/*
 * Name : file_delete ( char *filename )
 * Desc : deletes a named file
 * In   : char *filename   - the name of the file
 * Out  : pointer to an error block
 */

extern _kernel_oserror *file_delete ( char *filename )
{
_kernel_swi_regs  r;

  r.r[0] = Delete;
  r.r[1] = (int) filename;
  return((last_oserror = _kernel_swi(OS_File,&r,&r)));
}



/*
 * Name : file_createfile
 * Desc : creates an empty file of specified size
 * In   : char *filename     - name of file to create
 *        int   filetype     - filetype
 *        int   size         - size of file to create
 * Out  : pointer to an error block
 */

extern _kernel_oserror *file_createfile ( char *filename, int filetype, int size )
{
_kernel_swi_regs r;

  r.r[0] = CreateFile;
  r.r[1] = (int) filename;
  r.r[2] = filetype;
  r.r[4] = 0;
  r.r[5] = size;
  return((last_oserror = _kernel_swi(OS_File,&r,&r)));
}



/*
 * Name : file_createdir
 * Desc : creates a directory
 * In   : char *filename  - name of directory
 *        int entries     - number of files allowed in directory
 * Out  : pointer to an error block
 */

extern _kernel_oserror *file_createdir ( char *filename, int entries )
{
_kernel_swi_regs r;

  r.r[0] = CreateDir;
  r.r[1] = (int) filename;
  r.r[4] = entries;
  return((last_oserror = _kernel_swi(OS_File,&r,&r)));
}


  
/*
 * Name : file_load
 * Desc : loads a named file into memory
 * In   : char *filename    - name of file to load
 *        int   address     - address of memory to load file in
 * Out  : pointer to error block
 */

extern _kernel_oserror *file_load ( char *filename, int address )
{
_kernel_swi_regs r;

  r.r[0] = LoadFile;
  r.r[1] = (int) filename;
  r.r[2] = address;
  r.r[3] = 0;
  last_oserror = _kernel_swi(OS_File,&r,&r);
  return(last_oserror);
}



/**********************************************************
 * OS_Args calls                                          *
 * -------------                                          *
 *                                                        *
 * These calls call the SWI' as detailed in the RISC OS   *
 * v2.00 PRM                                              *
 *                                                        *
 * They deal mainly with the reading of open files        *
 * arguments                                              *
 *                                                        *
 **********************************************************/

  
/*************************************************
 * Reason codes etc                              *
 *************************************************/

/*-- OS Args --*/

#define OS_Args     0x09
#define ReadSeqPtr     0
#define WriteSeqPtr    1
#define ReadExt        2
#define WriteExt       3
#define ReadSize       4
#define ReadEOF        5
#define EnsureSize     6
#define HandleInfo   254
#define Flush        255

/*
 * Name : file_read_seqptr
 * Desc : reads the files sequential pointer
 * In   : int  handle   - file handle
 *        int *seqptr   - desination for seq ptr
 * Out  : pointer to error block
 */

extern _kernel_oserror *file_read_seqptr ( int handle, int *seqptr )
{
_kernel_swi_regs r;

  r.r[0] = ReadSeqPtr;
  r.r[1] = handle;
  if((last_oserror = _kernel_swi(OS_Args,&r,&r)) == NULL)
    *seqptr = r.r[2];
  return(last_oserror);
}
                   


/*
 * Name : file_write_seqptr
 * Desc : writes the files sequential pointer
 * In   : int  handle  - file handle
 *        int  seqptr  - new seq ptr
 * Out  : pointer to error block
 */

extern _kernel_oserror *file_write_seqptr ( int handle, int seqptr )
{
_kernel_swi_regs  r;

  r.r[0] = WriteSeqPtr;
  r.r[1] = handle;
  r.r[2] = seqptr;
  return((last_oserror = _kernel_swi(OS_Args,&r,&r)));
}



/*
 * Name : file_read_ext
 * Desc : reads a files open extent
 * In   : int  handle   - file handle
 *        int *ext      - destination for extent
 * Out  : pointer to error block
 */

extern _kernel_oserror *file_read_ext ( int handle, int *ext )
{
_kernel_swi_regs r;

  r.r[0] = ReadExt;
  r.r[1] = handle;
  if((last_oserror = _kernel_swi(OS_Args,&r,&r)) == NULL)
    *ext = r.r[2];
  return(last_oserror);
}



/*
 * Name : file_write_ext
 * Desc : writes a files open extent
 * In   : int  handle   - file handle
 *        int  ext      - new extent
 * Out  : pointer to error block
 */

extern _kernel_oserror *file_write_ext ( int handle, int ext )
{
_kernel_swi_regs r;

  r.r[0] = ReadExt;
  r.r[1] = handle;
  r.r[2] = ext;
  return((last_oserror = _kernel_swi(OS_Args,&r,&r)));
}                                                     



/*
 * Name : file_read_allocsize
 * Desc : reads a files allocated size
 * In   : int  handle   - file handle
 *        int *size     - destination for size
 * Out  : pointer to error block
 */

extern _kernel_oserror *file_read_allocsize ( int handle, int *size )
{
_kernel_swi_regs r;

  r.r[0] = ReadSize;
  r.r[1] = handle;
  if((last_oserror = _kernel_swi(OS_Args,&r,&r)) == NULL)
    *size = r.r[2];
  return(last_oserror);
}
                      


/*
 * Name : file_read_EOF
 * Desc : reads a files EOF state
 * In   : int  handle - files handle
 * Out  : TRUE if EOF else FALSE
 */

extern BOOL file_read_eof ( int handle )
{
_kernel_swi_regs  r;
 
  r.r[0] = ReadEOF;
  r.r[1] = handle;
  last_oserror = _kernel_swi(OS_Args,&r,&r);
  return(r.r[2]);
}



/*
 * Name : file_ensure_size
 * Desc : Ensures an open files size
 * In   : int  handle  - file handle
 *        int  size    - size to ensure to
 * Out  : Pointer to error block
 */

extern _kernel_oserror *file_ensure_size ( int handle, int size )
{
_kernel_swi_regs r;

  r.r[0] = EnsureSize;
  r.r[1] = handle;
  r.r[2] = size;
  return((last_oserror = _kernel_swi(OS_Args,&r,&r)));
}
       
            

#ifndef FILE_INFO_BITS_DEFINED
#define FILE_INFO_BITS_DEFINED
#define STREAM_INTERACTIVE       4
#define STREAM_SUPPORTS_GBPB     8
#define OBJECT_DIRECTORY        16
#define READ_ACCESS             32
#define WRITE_ACCESS            64
#define OBJECT_WRITTEN         128
#define END_OF_FILE            256
#define STREAM_UNBUFFERED      512
#define STREAM_UNALLOCATED    1024
#define STREAM_CRITICAL       2048
#define DATA_LOST             4096
#endif
 

/*
 * Name : file_read_handleinfo 
 * Desc : reads information on a files handle
 * In   : int handle   - file handle
 * Out  : status of file handle
 */

extern int file_read_handleinfo ( int handle )
{
_kernel_swi_regs  r;

  r.r[0] = HandleInfo;
  r.r[1] = handle;
  last_oserror = _kernel_swi(OS_Args,&r,&r);
  return(r.r[0]);
}
 


/*
 * Name : file_flush
 * Desc : ensres that all buffered data is written
 * In   : int  handle   - file handle
 * Out  : pointer to error block
 */

extern _kernel_oserror *file_flush ( int handle )
{
_kernel_swi_regs r;

  r.r[0] = Flush;
  r.r[1] = handle;
  return((last_oserror = _kernel_swi(OS_Args,&r,&r)));
}



/**********************************************************
 * OS_BGet/BPut & OS_GBPB                                 *
 * ----------------------                                 *
 *                                                        *
 * These calls call the SWI' as detailed in the RISC OS   *
 * v2.00 PRM                                              *
 *                                                        *
 * They deal mainly with the reading and writing of       *
 * byte(s) to open files                                  *
 *                                                        *
 **********************************************************/

  
/*************************************************
 * Reason codes etc                              *
 *************************************************/

#define OS_BGet        0x0A
#define OS_BPut        0x0B
#define OS_GBPB        0x0C
#define WriteBytesSEQ     1
#define WriteBytes        2
#define ReadBytesSEQ      3
#define ReadBytes         4


/*
 * Name : file_readabyte
 * Desc : reads a byte from an open file
 * In   : int handle   - file handle
 * Out  : int          - byte read
 * Info : will return -1 if an error is encountered
 */

extern int file_readabyte ( int handle )
{
_kernel_swi_regs  r;

  r.r[1] = handle;
  last_oserror = _kernel_swi(OS_BGet,&r,&r);
  if(last_oserror != NULL)
    return(-1);
  return(r.r[0]);
}



/*
 * Name : file_writeabyte
 * Desc : writes a byte to an open file
 * In   : int handle    - file handle
 *        int byte      - byte to write
 * Out  : pointer to error block
 */

extern _kernel_oserror *file_writeabyte ( int handle, int byte )
{
_kernel_swi_regs  r;

  r.r[0] = byte;
  r.r[1] = handle;
  return((last_oserror = _kernel_swi(OS_BPut,&r,&r)));
}



/*
 * Name : file_writebytes
 * Desc : writes a buffer to an open file
 * In   : int   handle     - file handle
 *        char *buffer     - pointer to buffer to write
 *        int   offset     - offset in buffer to write from
 *        int   nwrite     - number of bytes to write to file
 *        int   seqptr     - sequential file pointer
 * Out  : pointer to error block    
 * Info : if seqptr == -1 then writing will start from current
 *        sequential file pointer
 */

extern _kernel_oserror *file_writebytes ( int handle, char *buffer,
                                          int offset, int nwrite,
                                          int seqptr               )
{                                
_kernel_swi_regs  r;

  if(seqptr == -1)
    r.r[0] = WriteBytes;
  else
    r.r[0] = WriteBytesSEQ;
  r.r[1] = handle;
  r.r[2] = ((int) buffer) + offset;
  r.r[3] = nwrite;
  if(r.r[0] == WriteBytesSEQ)
    r.r[4] = seqptr;
  last_oserror = _kernel_swi(OS_GBPB,&r,&r);
  return(last_oserror);
}




/*
 * Name : file_readbytes
 * Desc : writes a buffer to an open file
 * In   : int   handle     - file handle
 *        int   buffer     - pointer to buffer 
 *        int   nread      - number of bytes to read
 *        int   seqptr     - sequential file pointer
 * Out  : pointer to error block    
 * Info : if seqptr == -1 then writing will start from current
 *        sequential file pointer
 */

extern _kernel_oserror *file_readbytes  ( int handle, char *buffer,
                                          int nread,  int seqptr  )
{                                
_kernel_swi_regs  r;

  if(seqptr == -1)
    r.r[0] = ReadBytes;
  else
    r.r[0] = ReadBytesSEQ;
  r.r[1] = handle;
  r.r[2] = (int) buffer;
  r.r[3] = nread;
  if(r.r[0] == ReadBytesSEQ)
    r.r[4] = seqptr;
  last_oserror = _kernel_swi(OS_GBPB,&r,&r);
  return(last_oserror);
}



/**********************************************************
 * OS_Find                                                *
 * -------                                                *
 *                                                        *
 * These calls call the SWI' as detailed in the RISC OS   *
 * v2.00 PRM                                              *
 *                                                        *
 * They deal mainly with the opening of files             *
 *                                                        *
 **********************************************************/

  
/*************************************************
 * Reason codes etc                              *
 *************************************************/

#define OS_Find     0x0D

#ifndef OPEN_TYPES
#define OPEN_TYPES
#define OPEN_EXIST_READ         "r"
#define OPEN_NEW_READ_WRITE     "wr"
#define OPEN_EXIST_READ_WRITE   "wr+"
#endif

/*
 * Name : file_open 
 * Desc : opens a specified file
 * In   : char *filename    - the file to open
 *        int  *handle      - destination for file handle
 *        char *oa          - open access indicator
 * Out  : pointer to error block
 */

extern _kernel_oserror *file_open ( char *filename, int *handle, char *oa )
{
_kernel_swi_regs  r;

  if(strcmp(oa,OPEN_EXIST_READ) == 0)
    r.r[0] = 0x4C;
  else
  {
    if(strcmp(oa,OPEN_NEW_READ_WRITE) == 0)
      r.r[0] = 0x8C;
    else
    {
      if(strcmp(oa,OPEN_EXIST_READ_WRITE) == 0)
        r.r[0] = 0xCC;
      else
      {
         r.r[0] = 0x4C;
      }
    }
  }
  r.r[1] = (int) filename;
  last_oserror = _kernel_swi(OS_Find,&r,&r);
  *handle = r.r[0];
  return(last_oserror);
}



/*
 * Name : file_close 
 * Desc : closes a file
 * In   : int handle  -  file handle
 * Out  : pointer to error block
 */
     
extern _kernel_oserror *file_close ( int handle )
{
_kernel_swi_regs r;

  r.r[0] = 0;
  r.r[1] = handle;
  return((last_oserror = _kernel_swi(OS_Find,&r,&r)));
}

/*****************************************
 * End                                   *
 *****************************************/

