/* $Header: archimedes.mus,v 3.0.1.1 90/08/09 04:05:21 lwall Locked $
 *
 * $Log:	archimedes.mus,v $
 * Revision 3.0.1.1  90/08/09  04:05:21  lwall
 * patch19: Initial revision
 * 
 */

#include "EXTERN.h"
#include "perl.h"

static enum uservars {
    UV_Mode,
    UV_Rows,
    UV_Cols
};

static enum usersubs {
    US_osrdch,
    US_oswrch,
    US_osrdstr,
    US_oswrstr,
    US_fx
};

static int usersub PROTO((int, int, int));
static int userset PROTO((int, STR *));
static int userval PROTO((int, STR *));

#define fx		_kernel_osbyte

void
userinit()
{
    struct ufuncs uf;
    char *filename = "C.Archimedes";

    uf.uf_set = userset;
    uf.uf_val = userval;

#define MAGICVAR(name, ix) (uf.uf_index = ix, magicname(name, (char *)&uf, sizeof uf))

    MAGICVAR("Mode",	UV_Mode);
    MAGICVAR("Rows",	UV_Rows);
    MAGICVAR("Cols",	UV_Cols);

    make_usub("osrdch",		US_osrdch,	usersub, filename);
    make_usub("oswrch",		US_oswrch,	usersub, filename);
    make_usub("osrdstr",	US_osrdstr,	usersub, filename);
    make_usub("oswrstr",	US_oswrstr,	usersub, filename);
    make_usub("fx",		US_fx,		usersub, filename);
}

static int
usersub(ix, sp, items)
int ix;
register int sp;
register int items;
{
    STR **st = stack->ary_array + sp;
    register STR *Str;		/* used in str_get and str_gnum macros */

    switch (ix) {
    case US_osrdch:
        if (items != 0)
            fatal("Usage: &osrdch()");
        else {
            int retval;
	    char retch;

            retval = _kernel_osrdch();
	    if (retval < 0)
		st[0] = &str_undef;
	    else {
		retch = retval;
		str_nset(st[0], &retch, 1);
	    }
        }
        return sp;

    case US_oswrch:
        if (items != 1)
            fatal("Usage: &oswrch($char)");
        else {
	    int ch = (int)str_gnum(st[1]);

	    if (_kernel_oswrch(ch) < 0)
		st[0] = &str_undef;
	    else
		str_numset(st[0], 1.0);
        }
        return sp;

    case US_osrdstr:
	if (items < 1 || items > 3)
	    fatal("Usage: &osrdstr($len,$lo_asc,$hi_asc)");
	else {
	    STRLEN len = (int)str_gnum(st[1]);
	    int lo_asc = (items >= 2 ? (int)str_gnum(st[2]) : 32);
	    int hi_asc = (items >= 3 ? (int)str_gnum(st[3]) : 255);

	    /* Register buffer for the OS call */
	    _kernel_swi_regs regs;

	    /* Allocate the buffer, allowing 1 extra character for the CR */
	    STR_GROW(st[0], len+1);

	    regs.r[0] = (int)st[0]->str_ptr;
	    regs.r[1] = (int)len;
	    regs.r[2] = lo_asc;
	    regs.r[3] = hi_asc;

	    /* Clear escape flag */
	    _kernel_escape_seen();

	    if (_kernel_swi(OS_ReadLine,&regs,&regs) || _kernel_escape_seen())
	    {
		/* Return undef on an error or escape */
		st[0] = &str_undef;
	    }
	    else
	    {
		/* Set the result string to the correct length (the second
		 * parameter of 0 to str_nset() means leave the string's
		 * value unchanged)
		 */
		str_nset(st[0], 0, regs.r[1]);
	    }
	}
	return sp;

    case US_oswrstr:
	if (items != 1)
	    fatal("Usage: &oswrstr($str)");
	else {
	    char *str = str_get(st[1]);
	    STRLEN len = st[1]->str_len;
	    _kernel_swi_regs regs;

	    regs.r[0] = (int)str;
	    regs.r[1] = (int)len;
	    if (_kernel_swi(OS_WriteN,&regs,&regs))
		st[0] = &str_undef;
	    else
		str_numset(st[0], 1.0);
	}
	return sp;

CASE int fx
I       int             op
I       int             x
I       int             y
END

    default:
	fatal("Unimplemented user-defined subroutine");
    }
    return sp;
}

static int
userval(ix, str)
int ix;
STR *str;
{
    int i;
    int in[2];
    int out[2];
    _kernel_swi_regs regs;

    switch (ix) {
    case UV_Mode:
	i = fx(135,0,0);
	i = (i >> 8) & 0xFF;
	str_numset(str, (double)i);
	break;
    case UV_Rows:
	in[0] = 257;
	in[1] = -1;
	regs.r[0] = (int)in;
	regs.r[1] = (int)out;
	if (_kernel_swi(OS_ReadVduVariables,&regs,&regs))
	    str_numset(str, -1.0);
	else
	    str_numset(str, (double)(out[0]+1));
	break;
    case UV_Cols:
	in[0] = 256;
	in[1] = -1;
	regs.r[0] = (int)in;
	regs.r[1] = (int)out;
	if (_kernel_swi(OS_ReadVduVariables,&regs,&regs))
	    str_numset(str, -1.0);
	else
	    str_numset(str, (double)out[0]);
	break;
    }
    return 0;
}

static int
userset(ix, str)
int ix;
STR *str;
{
    int i;

    switch (ix) {
    case UV_Mode:
	i = (int)str_gnum(str);
	_kernel_oswrch(22);
	_kernel_oswrch(i);
	break;
    }
    return 0;
}
