/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "Licence").
 * You may not use this file except in compliance with the Licence.
 *
 * You can obtain a copy of the licence at RISC OS path @.^.LICENCE
 * or  http://www.riscosdev.com/lanman98/LICENCE.CDDL
 * See the Licence for the specific language governing permissions
 * and limitations under the Licence.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the Licence file. If applicable, add the
 * following below this CDDL HEADER, with the fields enclosed by
 * brackets "[]" replaced with your own identifying information:
 * Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
 
/*
 *   Portions Copyright 1996 Warm Silence Software Ltd.
 */

/******************************************************/
/*                                                    */
/* Name: PGfs.c                                       */
/* Author: Paul Gardiner.                             */
/* Function:                                          */
/*   Provides a library of file access functions for  */
/* use with either of the two modules, PGscn or       */
/* PGwin. They CAN be used in isolation.              */
/*                                                    */
/******************************************************/

#include <stdlib.h>
#include <string.h>
#include "kernel.h"
#include "swis.h"
#include "PGerr.h"
#include "PGfs.h"

#ifndef NULL
#define NULL (0)
#endif

static _kernel_swi_regs regs;

void FsDelete(char *name)
{
    regs.r[0] = 27;
    regs.r[1] = (int) name;
    regs.r[3] = 0;
    _kernel_swi(OS_FSControl, &regs, &regs);
}

int FsType(char *name)
{
    regs.r[0] = 17;
    regs.r[1] = (int) name;
    _kernel_swi(OS_File, &regs, &regs);   /* May not exist ??? */
    return (regs.r[2] >> 8) & 0xFFF;
}

void FsSetType(char *name, int ft)
{
    regs.r[0] = 18;
    regs.r[1] = (int) name;
    regs.r[2] = ft;
    _kernel_swi(OS_File, &regs, &regs);   /* May not exist ??? */
}

int FsSize(char *name)
{
    regs.r[0] = 17;
    regs.r[1] = (int) name;
    _kernel_swi(OS_File, &regs, &regs);
    if(regs.r[0] == 1 || regs.r[0] == 3)
        return regs.r[4];
    else
        return -1;
}

fs_handle FsOpen(char *name)
{
    _kernel_oserror *err;

    regs.r[0] = 17;
    regs.r[1] = (int) name;
    _kernel_swi(OS_File, &regs, &regs);
    switch(regs.r[0])
    {
        case 0:
            Error("%s not found", name);
            return 0;
        case 2:
            Error("%s is a directory", name);
            return 0;
    }
    regs.r[0] = 0x43;
    regs.r[1] = (int) name;
    regs.r[2] = 0;
    err = _kernel_swi(OS_Find, &regs, &regs);
    if(err)
        Error("Error from RISCOS: ""%s""", (char *) err + 4);
    return regs.r[0];
}

void FsClose(fs_handle fh)
{
    regs.r[0] = 0;
    regs.r[1] = fh;
    _kernel_swi(OS_Find, &regs, &regs);
}

void FsRead(fs_handle fh, void *buf, int size)
{
    regs.r[0] = 4;
    regs.r[1] = fh;
    regs.r[2] = (int) buf;
    regs.r[3] = size;
    _kernel_swi(OS_GBPB, &regs, &regs);
}

void FsReadAt(fs_handle fh, fs_pointer fp, void *buf, int size)
{
    _kernel_oserror *err;

    regs.r[0] = 3;
    regs.r[1] = fh;
    regs.r[2] = (int) buf;
    regs.r[3] = size;
    regs.r[4] = fp;
    err = _kernel_swi(OS_GBPB, &regs, &regs);
    if(err)
    {
        int i;
        Error("Error from RISCOS: ""%s""", (char *) err + 4);
        for(i = 0; i < 10 && err; ++i)
        {
            regs.r[0] = 3;
            regs.r[1] = fh;
            regs.r[2] = (int) buf;
            regs.r[3] = size;
            regs.r[4] = fp;
            err = _kernel_swi(OS_GBPB, &regs, &regs);
        }
        if(err)
            ErrorFatal("Multiply occuring error: ""%s""", (char *) err + 4);
    }
}

char *FsName(int handle)
{
    _kernel_swi_regs regs;
    static char *buf = NULL;
    static int bufsize = 0;

    regs.r[0] = 7;
    regs.r[1] = handle;
    regs.r[2] = 0;
    regs.r[5] = 0;
    _kernel_swi(OS_Args, &regs, &regs);
    regs.r[5] = 1 - regs.r[5];
    if(regs.r[5] > bufsize)
    {
        if(buf != NULL) free(buf);
        bufsize = regs.r[5];
        buf = malloc(bufsize);
        if(buf == NULL)
        {
            bufsize = 0;
            return NULL;
        }
    }
    regs.r[2] = (int) buf;
    regs.r[0] = 7;
    regs.r[1] = handle;
    _kernel_swi(OS_Args, &regs, &regs);
    return buf;
}

char *FsEnumerateDir(char *p)
{
    static char *path = NULL;
    static char leaf[256];
    static int i = -1;
    _kernel_swi_regs regs;

    if(p)
    {
        if(path) free(path);
        path = malloc(strlen(p)+1);
        strcpy(path, p);
        i = 0;
    }
    if(i == -1)
    {
        if(path) free(path);
        path = NULL;
        return NULL;
    }
    regs.r[0] = 9;
    regs.r[1] = (int) path;
    regs.r[2] = (int) leaf;
    regs.r[3] = 1;
    regs.r[4] = i;
    regs.r[5] = 256;
    regs.r[6] = 0;
    if(_kernel_swi(OS_GBPB, &regs, &regs))
        return NULL;
    i = regs.r[4];
    if(regs.r[3] == 0)
    {
        if(path) free(path);
        path = NULL;
        return NULL;
    }
    return leaf;
}
