
/***************************************/
/*                                     */
/*              osem.c                 */
/*                                     */
/* Operating system emulation routines */
/* for embedded system example ROM     */
/* monitor.                            */
/*                                     */
/*          Copyright (c) 1990         */
/*          Pasquale J. Villani        */
/*          All Rights Reserved        */
/*                                     */
/*                                     */
/***************************************/

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>


/* convience defines                            */
#define STDIN   0
#define STDOUT  1
#define STDERR  2
#define MAXFD   3
#define BUFSIZ  512         /* buffers are 512 for this vsn */

#ifndef TRUE
#define TRUE    1
#endif
#ifndef FALSE
#define FALSE   0
#endif
#ifndef ERROR
#define ERROR   -1
#endif
#ifndef OK
#define OK  0
#endif
#ifndef EOF
#define EOF -1
#endif


/* make errno accessible to the entire file             */
extern int errno;

/* special data structure for ioctl optional argument           */
union arg
{
    int i;
    void    *p;
};


/* a simple file table to keep track of stdin & stdout status       */
static char fd[MAXFD] =
{
    FALSE,          /* stdin                */
    FALSE,          /* stdout               */
    FALSE           /* stderr               */
};


/* a simple set of i/o buffers for input buffering          */
struct _buf
{
    int nbytes;
    char    *bp;
    char    buf[BUFSIZ];
};

static struct _buf iobuf =
{
    -1, (char *)0
};



/*                                  */
/* smatch:                              */
/*  match two strings. return true if equal             */
/*                                  */
static int smatch(s1, s2)
char *s1, *s2;
{
    while(*s1 != '\0')
    {
        if(*s1 != *s2)
            break;
        ++s1;
        ++s2;
    }
    return s1 == s2;
}



/*                                  */
/* open:                                */
/*  open a file for read or write                   */
/*  follows posix specification                 */
/*                                  */
int open(path, oflag, mode)
char *path;
int oflag, mode;
{
    if(smatch(path, "/dev/con") || ((oflag & O_RDWR) == O_RDWR))
    {
        errno = EACCES;
        return ERROR;       /* error - only console allowed */
    }
    /* for this system, only stdin and stdout are available     */
    /* based on oflag and availability, assign appropraie fd    */
    if((oflag & O_RDONLY) && !fd[STDIN])
    {
        fd[STDIN] = TRUE;
        return STDIN;
    }
    else if(oflag & O_WRONLY)
    {
        fd[STDOUT] = TRUE;
        return STDOUT;
    }
    else
    {
        errno = EACCES;
        return ERROR;
    }
}


/*                                  */
/* close:                               */
/*  close a file                            */
/*                                  */
int close(fildes)
int fildes;
{
    if((fildes < 0) || (fildes > MAXFD) || !(fd[fildes]))
    {
        errno = EBADF;
        return ERROR;
    }
    fd[fildes] = FALSE;
    return OK;
}


/*                                  */
/* ioctl:                               */
/*  direct device control                       */
/*                                  */
int ioctl(fildes, request, arg)
int fildes, request;
union arg arg;
{
    errno = EINVAL;
    return ERROR;
}


/*                                  */
/* write:                               */
/*  write to a file                         */
/*                                  */
int write(fildes, buf, nbyte)
int fildes;
void *buf;
unsigned int nbyte;
{
    int cnt = nbyte;

    if(fildes != STDOUT && fildes != STDERR)
    {
        errno = EBADF;
        return ERROR;
    }
    while(cnt-- > 0)
    {
        if(*(char *)buf == '\n')
            _cout('\r');
        _cout(*((char *)buf)++);
    }
    return nbyte;
}


int read(fildes, buf, nbyte)
int fildes;
void *buf;
unsigned int nbyte;
{
    register char *bp;
    register int c;

    if(fildes != STDIN)
    {
        errno = EBADF;
        return ERROR;
    }
    if(iobuf.nbytes <= 0)
    {
        bp = iobuf.buf;
        iobuf.nbytes = 0;
        do
        {
            *bp++ = (_cout(c = _cin()));
            if(c == '\r')
                _cout('\n');
            ++iobuf.nbytes;
        } while(c != '\n' && c != '\r');
        iobuf.bp = iobuf.buf;
    }
    for(bp = iobuf.bp, c = 0; c < iobuf.nbytes && c <nbyte; c++)
    {
        *((char *)buf)++ = *bp == '\r' ? ++bp, '\n' : *bp++;
    }
        iobuf.bp = bp;
    iobuf.nbytes -= c;
    return c;
}


