/* open.c -- code for opening memory and making changes
 * copyright (c) 1984  American Information Systems Corporation
 *  Dock Williams
 *  October, 1984
 *
 */

#include "monitor.h"
#include "ascii.h"
#include "vctype.h"

#define ILEN	40
#define MAXVAL	9



open(argv)
char *argv[];
{
    register char c;
    register int j;
    int i;
    struct symbol *fsym();
    char istr[ILEN], iflag, sflag;

    iflag = 0;
    sflag = 0;

    /* coverting a symbol will load lmapsym with the desired mapping */
    lmapsym = 0;

    if (mapping == 0)
		mapping = (cflags & CF_PHYS) ? PHYS : getmap();
    if (*argv[0] == 0) psym(curaddr);
    else if(conv(argv[0],&curaddr)) {
		mapping = lmapsym ? lmapsym : getmap();
    }
    else return;

loop:
    while(!quitchk()) {
	if (sflag || iflag) {
		iflag = 0;
		sflag = 0;
	} else {
		dprint(curaddr, curbase, cursize);
	}

	c = getinput(istr,ILEN,1);

	i= strlen(istr);	/* i is positive if we got input */

	switch (c) {
	case '\0': continue;
	case '$':			/* change output format base */
	    if (istr[0] == 0) continue;
	    for (j=0;j<i;j++)
		    if (isalpha(istr[j])) break;
	    c = istr[j];
	    if (isupper(c)) c = tolower(c);
	    switch(c) {
	    case 'b':
	    case 'c':
	    case 'd':
	    case 'o':
	    case 'u':
	    case 'x':
		curbase = c; break;
	    case 's':
		sflag++;
		dprint(curaddr,'s',cursize);
		continue;
	    default:
		printf(" ?? "); break;
	    }
	    continue;
	case '\`':			/* open a byte location */
	case '\\':			/* open a word location */
	case '/':			/* open a double location */
	    if (i) 
		if (conv(istr,&i)) {
			curaddr = i;
			if (lmapsym != NULL) mapping = lmapsym;
		}
	    setcursize(c);
	    continue;
	case '-':			/* back up a specified size */
	    if (i) {
		if (conv(istr,&i)) curaddr -= i;
		else return;
	    } else curaddr -= cursize;
	    OUTCHR('\n');
	    break;
	case '^':			/* back up current size */
	    if (i) {
		if (conv(istr,&i)) zap(curaddr,i,cursize);
		else return;
	    }
	    curaddr -= cursize;
	    OUTCHR('\n');
	    break;
	case CR:			/* write location and quit */
	    if (i) {
		if (conv(istr,&i)) zap(curaddr,i,cursize);
		else return;
	    }
	    OUTCHR('\n');
	    return;
	case LF:			/* next location */
	    if (i) {
		if (conv(istr,&i)) zap(curaddr,i,cursize);
		else return;
	    }
	    if (curbase == 'u')
		curaddr += instr_len;
	    else curaddr += cursize;
	    OUTCHR(c);
	    break;
	case '+':	/* go farward a specified size */
	    if (i) {
		if (conv(istr,&i)) curaddr += i;
		else return;
	    } else curaddr += cursize;
	    OUTCHR('\n');
	    break;
		/* print what is pointed to by the current location */
	case '@':
	    curaddr = mrdquad(curaddr, mapping);
	    if ( ((curaddr < (int)&env->fpu) ||
		  (curaddr > (int)&env->msr)) &&
		 (mapping == PHYS) )
			mapping = (cflags & CF_PHYS) ? PHYS : getmap();
	    OUTCHR('\n');
	    break;
	case 'u':
	    OUTCHR(':');
	    i = disasm(curaddr,1);
	    OUTCHR(' ');
	    iflag++;
	    continue;
	default:
	    return;
	}

    psym(curaddr);
    }
}




zap(address, value, size)
unsigned value;
/*
 * write a value to the address for the size specified
 */
{
    switch(size) {
    case 1:
	mwrtmbyte(address, mapping, value);
	break;
    case 2:
	mwrtmword(address, mapping, value);
	break;
    case 4:
	mwrtmquad(address, mapping, value);
	break;
    }
}



dprint(addr, base, size)
    register unsigned int addr;
    char	base,size;
/*
 * display data at address addr	in base for size given
 */
{
    register int i;
    register char *paddr;

    switch(base) {
    case 'b':		/* print as binary (bit pattern) */
	printf("b:");
	switch(size) {
	case 1:	printf("%8b", mrdbyte(addr,mapping)); break;
	case 2:	printf("%16b", mrdword(addr,mapping)); break;
	case 4:	printf("%32b", mrdquad(addr,mapping)); break;
	}
	break;
    case 'o':		/* print as octal */
	printf("o:");
	switch(size) {
	case 1:	printf("%3o", mrdbyte(addr,mapping)); break;
	case 2:	printf("%6o", mrdword(addr,mapping)); break;
	case 4:	printf("%12o", mrdquad(addr,mapping)); break;
	}
	break;
    case 'd':		/* print as decimal */
	printf("d:");
	switch(size) {
	case 1:	printf("%3d", mrdbyte(addr,mapping)); break;
	case 2:	printf("%5d", mrdword(addr,mapping)); break;
	case 4:	printf("%10d", mrdquad(addr,mapping)); break;
	}
	break;
    case 'x':
	printf("0x");
	switch(size) {
	case 1:	printf("%2x", mrdbyte(addr,mapping)); break;
	case 2:	printf("%4x", mrdword(addr,mapping)); break;
	case 4:	printf("%8x", mrdquad(addr,mapping)); break;
	}
	break;
    case 'c':			/* print as character */
	printf("c:");
	i = cursize;
	for(paddr = (char *)addr; i > 0; paddr++,i--) {
	    prtsee(mrdbyte(paddr, mapping));
	}
	break;
    case 'u':			/* print disassembled */
	instr_len = disasm(addr,1);
	break;
    case 's':			/* print as a string */
	for(i=0,paddr=(char *)addr;i<512,!quitchk();i++,paddr++) {
	    if(mrdbyte(paddr, mapping) == '\0') break;
	    else prtsee(mrdbyte(paddr, mapping));
	}
	break;
    default:
	break;
    }
    printf("  ");
}



conv(s,result)
    char *s;
    unsigned int *result;
/*
 * convert input string to binary value
 */
{
    register int x, oc, vc;
    unsigned int val[MAXVAL];
    unsigned char op[MAXVAL-1];
    int lastx, rc;


    x = strlen(s);			/* find end of input string */
    vc = 0;				/* value and operator counts */
    oc = 0;		
    lastx = x;

    while (x--) {
	while ( x>0 && notop(s[x]) ) x--;	/* back up over operand */

#ifdef DEBUG1
	printf("   lastx=%x x=%x s[x]=%c   ",lastx,x,s[x]);
#endif

	/* if we have read only one character, if it is an operator */
	/* we dont have an operand to evaluate */
	if ( (x+1 < lastx) || (notop(s[x])) ) {	
	    if(atomcv(&s[(x==0 && (!isunop(s[x]))) ? x : x+1], &val[vc])) {
		vc++;
	    }
	    else return(0);			/* input error return */
	} 

	if (isunop(s[x])) {			/* is this a unary op */
	    if (vc==0) goto cverr;
	    switch(s[x]) {
	    case '~':	val[vc-1] = ~(val[vc-1]); break;
	    case '@':	val[vc-1] = mrdquad(val[vc-1], mapping); break;
	    default:	printf("cverr\n");
	    }
	} else if (isbinop(s[x])) {		/* is this a binary op */
	    if (vc==0) goto cverr;
	    if (x > 0) {
		op[oc] = s[x];
		oc++;
	    }
	    if (oc>1) {
		if(prec(op[oc-2]) > prec(s[x])) {
		    val[vc-2] = eval(op[oc-2],val[vc-1],val[vc-2]);
		    vc--;
		    oc--;
		    op[oc-1] = s[x];
		}
	    }
	} 

#ifdef DEBUG1
	printf("v0=%x v1=%x v2=%x vc=%x\n",val[0],val[1],val[2],vc);
	printf("o0=%c o1=%c o2=%c oc=%x\n",op[0],op[1],op[2],oc);
#endif

	while(x == 0 && oc > 0 && vc > 1) {
	    val[vc-2] = eval(op[oc-1],val[vc-1],val[vc-2]);
	    vc --;
	    oc --;
	}
	lastx = x;			/* last index of x during this pass */
	s[x] = '\0';			/* mark end of interpretted string */
    }
    *result = val[0];
    return(1);

cverr:
    printf("cverr\n");
    return(0);
}



    static
atomcv(s,result)
    char *s;
    unsigned int *result;
{
    register int i;
    char temp[MAXNAM];
    struct symbol *sp;
    short *shtptr;
    int *intptr;

    while(isspace(*s)) s++;			/* skip over leading space */

    if(isalpha(*s) || *s == '_' || *s == '.') {
	/* produce a string of chars in temp that could be a symbol name */
	bzero(temp,MAXNAM);
	for(i=0;notop(s[i]) && s[i] != '\0';i++) {
	    if(i >= MAXNAM) {
		s[i = (MAXNAM-1)] = '\0';
		temp[i] = '\0';
		break;
	    }
	    temp[i] = s[i];
	}

	/* if dot return value of current address */
	if (s[0] == '.' && s[1] == '\0') {
		*result = curaddr;
		return(1);
	}

	/* look for the symbol */
	if ((sp = fsym(symstart, temp)) != (struct symbol *)NULL) {
	    *result = sp->value;
	    /* this symbol's mapping is important so we save it here */
	    lmapsym = (sp->flags&S_PHYS) ? PHYS : 
				((cflags&CF_PHYS) ? PHYS : getmap());
	    return(1);
	}
    } else if(*s == '\'') {
	switch(*++s) {
	case 'x':
	    if(ishexs(++s)) {
		*result = atob(s,16); return(1);
	    } else goto atomerr;
	case 'd':
	    if(isdecs(++s)) {
		*result = atob(s,10); return(1);
	    } else goto atomerr;
	case 'o':
	    if(isocts(++s)) {
		*result = atob(s,8); return(1);
	    } else goto atomerr;
	case 'c':
	    s++;
	    switch(cursize) {
	    case 1:	
		    *result = *s; return(1);
	    case 2:
		    shtptr = (short *)s; *result = *shtptr;
		    return(1);
	    case 4:
		    intptr = (int *)s; *result = *intptr;
		    return(1);
	    }
	default:
	    goto atomerr;
	}
    } 
    if(ishexs(s)) {
	*result = atob(s,16);
	return(1);
    } else {
atomerr:
	printf("cverr\n");
	return(0);
    }
}   


atob(string, base)
    register char *string;
    short base;
/*
 * convert an alphanumeric number in given base to binary
 */
{
    register int x;

    x = 0;
    switch (base) {
    case 8:
	while (octal(*string)) x = (x * 8) + ctod(*string++);
	break;
    case 10:
	while (isdigit(*string)) x = (x * 10) + ctod(*string++);
	break;
    case 16:
	while (isxdigit(*string)) x = (x * 16) + ctox(*string++);
	break;
    default:
	printf("cverr\n");	/* 'should not happen' */
	return(0);
    }
    return(x);
}



    static
eval(op,arg1,arg2)
    register char op;
    int arg1,arg2;
{

#ifdef DEBUG1
    printf("eval: %c %x %x\n",op,arg1,arg2);
#endif

    switch(op) {
    case '+':	return(arg1+arg2);
    case '-':	return(arg1-arg2);
    case '/':	return(arg1/arg2);
    case '*':	return(arg1*arg2);
    case '%':	return(arg1%arg2);
    case '^':	return(arg1^arg2);
    case '|':	return(arg1|arg2);
    case '&':	return(arg1&arg2);
    default:	printf("cverr\n");
    }
}




    static
prec(c)
    char c;
{
    switch(c) {
    case '*':	return(5);
    case '/':	return(5);
    case '%':	return(5);
    case '+':	return(4);
    case '-':	return(4);
    case '&':	return(3);
    case '^':	return(2);
    case '|':	return(1);
    default:	printf("cverr\n");
    }
}



prtsee(c)
    register char c;
{
    register int i;

    i = c & 0x000000ff;

    if (i >= 0x80) {
	i &= 0x0000007f;
	c = (char)i;
	OUTCHR('<');
	prtsee(c); 
	OUTCHR('>');
    }

    /* map all control characters to printable characters */
    else if (c >= 0x00 && c <= 0x1f) {
	c += 0x40;
	printf("^%c",c);
	return;
    }

    /* if delete print something special */
    else if (c == RUBOUT) printf("<DEL>");

    /* otherwise just echo the character */
    else OUTCHR(c);

}



    static
ishexs(s)
    register char *s;
{
    for(;*s != '\0';s++) {
	if(isxdigit(*s)) continue;
	else return(0);
    }
    return(1);
}

    static
isdecs(s)
register char *s;
{
    for(;*s != '\0';s++) {
	if(isdigit(*s)) continue;
	else return(0);
    }
    return(1);
}

    static
isocts(s)
register char *s;
{
    for(;*s != '\0';s++) {
	if(octal(*s)) continue;
	else return(0);
    }
    return(1);
}



    static
notop(c)
char c;
{
	if(isbinop(c) || isunop(c)) return(0);
	else return(1);
}

    static
isbinop(c)
char c;
{
    switch(c) {
    case '*':
    case '/':
    case '%':
    case '+':
    case '-':
    case '&':
    case '^':
    case '|':
	return(1);
    default:
	return(0);
    }
}

    static
isunop(c)
char c;
{
    switch(c) {
    case '~':
    case '@':
	return(1);
    default:
	return(0);
    }
}



setcursize(c)
char c;
{
    switch(c) {
    case '\`': cursize = 1; break;
    case '\\': cursize = 2; break;
    case '/': cursize = 4; break;
    }
}

static octal(x) char x; { return ((x>='0') && (x<='7')); }

ctod(x) char x; { return ( x - '0' ); }

ctox(x) char x; { return ( isdigit(x) ? x-'0' : tolower(x)-'a'+10 ); }

