/*
*    MC 68000 C Library - Copyright 1985 to 1987 Microtec Research, Inc.
*    This program is the property of Microtec Research, Inc,
*/
/* This library assumes that the following UNIX style system routines exist:

char *sbrk (size) int size;
    This should increment the heap pointer by size bytes
    and return the old heap pointer.  If there is not enough space on the
    heap, it should return -1.

int open(filename,mode) char *filename; int mode;
    Opens the specified file, depending on the indicated mode,  the modes are
    0   => open for reading
    1   => open for writing
    2   => open for reading & writing (not used)
    1|_IO_EOF   => open for writing and seek to eof
    open should return a number between 0 and 19 that may be associated with
    an element in the iob array.  On failure it should return -1.

int creat(filename,prot) char *filename; int prot;
    Creates and opens (for writing) a file named filename with protection
    as specified by prot.  For things like terminals that cannot be created
    it should just open the device.  It should return a number between 0-19
    that may be associated with an iob array element.  On failure it should
    return -1.

int read(fno,buf,nbyte) int fno, nbyte; char *buf;
    Reads at most nbyte bytes into buf from the file connected to fno (where
    fno is one of the file descriptors returned by open() or creat()). It should
    return the number of bytes read (a value of 0 is used to indicate EOF),
    or a -1 on error.

int write(fno,buf,nbyte) int fno, nbyte; char *buf;
    Writes at most nbyte bytes into the file connected to fno (where fno is
    one of the file descriptors returned by open() or creat()) into buf.  It
    should return the number of bytes written, or a -1 to indicate an error.

int close(fno) int fno;
    Closes the file associated with the file descriptors fno (returned by open()
    or creat()).  Should return 0 if all goes well or -1 on error.

void _exit(code) int code;
    Exits from the program, with a status code specified by code.
    Should not return.

These routines should use the variable errno to explain what went wrong when
problems occur (the various error codes are defined in errno.h).

The following is a very trivial version of these calls (except sbrk()) that
assumes the following: 

  1. there is one input device of interest, and characters can be read
        from it by calling INCHRW() which returns an integer of value 0..255
        or -1 for error.
  2. there is one output device of interest, and characters can be written
        to it by calling OUTCHR (ch).  Its return will be ignored.
  3. there is a way of entering the program, setting up the heap and stack
        pointers, and then it will call START() which in turn calls the
        user's main() function.

The user still has to provide 4 routines (written in assembly language):
(1) initialization routine, (2) sbrk(), (3) INCHRW(), and (4) OUTCHR().

*/

#if 0
#define $DATASEG A5 
#endif

#include <stdio.h>
#include <errno.h>

#define eoln 1

			/*   eoln is used to indicate the end of line characters
                            for the host system.
                        eoln =  0   carriage return (13) as end of line, ex :
                                    Microtec 68000 simulator
                             =  1   carriage return (13) followed by line feed 
                                    (10) as end of line, ex : MSDOS, XRAY
                             =  2   line feed (10) as end of line, ex : UNIX
                       */
                                   

struct iobuf _iob[_NFILE];
int errno;

int _lastp;    /*   variable to be used in 'strtok'  */
int _randx;    /*   variable to be used in 'rand'    */
struct free_hdr {
        unsigned length;
        struct free_hdr *next;
} *_first, *_next;     /*   variable to be used in 'malloc'  */

unsigned short  _fp_status, _fp_control;


/* This is a sample of the START() rotuine which is called by the user's
   initialization routine to start a C program.  It opens stdin, stdout and
   stderr to the console.  Then it calls the user's main() function.

   new added: defines and initializes variables for run-time functions
   'strtok', 'malloc', 'rand'.

   Before entering START(), the execution environment should already be
   set up, including the heap, the stack, and, optionally, the command line.
*/

START (argc, argv, env)
int argc;
char *argv[], *env[];

{

    errno = 0;		     /* initialize error number for run-time function */
    _lastp = 0;                         /* initialize for 'strtok' */
    _randx = 1;                         /* initialize for 'rand'  */
    _first = (char *)0;                 /* initialize for 'malloc' */
    _next  = (char *)0;                 /* initialize for 'malloc' */
    memclr (_iob, sizeof(_iob));        /* initialze all files */

    fopen ("/dev/tty", "r");            /* stdin */
    fopen ("/dev/tty", "w");            /* stdout */
    fopen ("/dev/tty", "w");            /* stderr */

    exit (main (argc, argv, env));
}


static find_free()      /* returns the number of a free _iob structure */
{
    register int i;

    for (i=0; i < _NFILE; i++) {
        if (!(_iob[i].io_flags&(_IO_READ|_IO_WRITE)))
            return (i);
    }
    errno = EMFILE;
    return (-1);
}

open (ignore, mode)
char *ignore;
int mode;
{
    register int fno;

    if ((fno=find_free())== -1)
        return (-1);
    mode &= 3;
    _iob[fno].io_file = fno;
    if (mode != 1)
        _iob[fno].io_flags = _IO_READ;
    if (mode != 0)
        _iob[fno].io_flags |= _IO_WRITE;
    return (fno);
}

creat (ignore, prot)
char *ignore;
int prot;
{
    return (open (ignore, 1));
}

close (fno)
int fno;
{
    if (!(_iob[fno].io_flags&(_IO_READ|_IO_WRITE))) {
        errno = EBADF;
        return (-1);
    }
    _iob[fno].io_flags = 0;
    return (0);
}

read (fno,buf,size)
int fno;
register char *buf;
register int size;
{
    register int cnt= 0, ch;

    if (!(_iob[fno].io_flags&_IO_READ)) {
        errno = EBADF;
        return (-1);
    }
    while (--size >= 0) {
        if ((ch = INCHRW()) == -1) {    /* read in one char */
            errno = EIO;
            return (-1);
        }
/* Add this for file I/O, skip '\r'
        if (eoln == 1 && ch == '\r') continue;  
*/
        if (eoln == 0 && ch == '\r') ch = '\n'; /* replace '\r' by '\n' */
        *(buf++) = ch;
        cnt++;
        if (ch == '\r' || ch == '\n')   /* CR or LF terminates the read */
            break;
    }
    return (cnt);
}

write (fno,buf,size)
int fno;
register char *buf;
register int size;
{
    register int cnt= 0;

    if (!(_iob[fno].io_flags&_IO_WRITE)) {
        errno = EBADF;
        return (-1);
    }
    while (--size >= 0) {
        if (eoln == 0 && *buf == '\n') *buf = '\r';  /* replace by '\r' */
        if (eoln == 1 && *buf == '\n') OUTCHR('\r'); /* output a '\r' first */
        OUTCHR (*(buf++));              /* output one char */
        cnt++;
    }
    return (cnt);
}

void _exit(code)
int code;               /* status code is being ignored here */
{
    asm("\tSTOP\t#$2700");
}


