/* **************************************************************
 *								*
 *			  MACHINE3.C				*
 *		MACHINE TABLE UTILITY ROUTINES			*
 *		  last modified 02/22/84 dsb			*
 *								*
 ************************************************************** */

#include "libc.h"
#include "machine.h"
#include "hardio.h"

#define MAX_PROD  20	   /* consider any higher product numbers invalid */
#define MAX_MACH  128

/* #define DBUG 1  */


map_test(map,bit)	    /* test a bit in a bit map */
char map[];		    /* always return FALSE if bit to test is FF or -1*/
int bit;
{
    return(((bit & 0xFF)!=0xFF)  && (map[bit/8] & (1<<(bit % 8))));
}


wait_user()
{
    char a;

    printf("\nHit RETURN to continue, <ctl-C> to abort: ");
    dgets(&a,1);				       
    if(a==0x03)
	bye();
}

waitkey()	/* get a char, throw in bit bucket */
{
    printf("\nPress any key to continue --> ");
    bios(3,0,0);
    printf("%c\t\t\t\t\t%c",CR,CR);   /* wipe out prompt line */
}

check_wait()	/* check for pause request, hang on until released */
{		/* pause request comes from kbd only, NOT stdin!! */
    if(bdos(11,0))
    {
	bdos(1,0);	      /* get key into bit bucket */
	bdos(1,0);	      /* wait for next one & eat it too */
    }
    return();
}
/*page*/

yorn(msg)
char *msg;
{
    char a;
    int i;

    do
    {
	printf("%s (Y/N)? --> ",msg);
	i = dgets(&a,1);
	a = toupper(a);
    } while((i != 1) || ((a != 'Y') && (a != 'N')));
    return(a);
}


is_correct()
{
    return(yorn("\nIs this correct ") == 'Y');
}

/*page*/
dgets(buf,max)	    /* get a string from stdin, terminated by <cr>  */
char *buf;	    /* or when max chars have been entered.  */
int max;	    /* don't put the <cr> in the string; return */
{		    /* the number of characters in the string. */
    char a;
    register int i,j;
    char tempbuf[20];

    if(max > 20)
    {
	printf("\n*BUG* call to dgets wants too many chars (%d)",max);
	return(0);
    }

    for(i=0; (i<20) && ((a=getchar()) != '\n'); i++)
	switch(a)
	{
	    default:	tempbuf[i] = a;
			break;
	    case DEL:	if(i)
			    printf("%c",BS);
	    case BS:	if(i)
			{     
			    printf(" %c",BS);
			    i--;
			}
			i--;
			break;
	    case CTRL_X:
			while(i)
			{
			    printf("%c %c",BS,BS);
			    i--;
			}
			i--;
			break;
	} /* switch on input character */

    if(i==20)			     /* if we exited because of full buffer */
	while((a=getchar()) != '\n')	/* eat chars until <cr>  */
	    ;
    for(j = 0; (j<i) && (j<max); j++)	  /* copy into user's buffer */
	*buf++ = tempbuf[j];

    return(i);
} /* dgets */

/*page*/



long gethex(minlen,maxlen)   /* get a valid hex number, <cr> to end */
int minlen,maxlen;
{
    char conbuf[8];
    register int count;

    error = abort_req = FALSE;

    clear(conbuf,8,'\0');
    if(!(count = dgets(conbuf,maxlen)))
    {
	abort_req = TRUE;
	return(0L);
    }
    if((count<minlen) || (count>maxlen))
    {
	error = TRUE;
	return(0L);
    }
    if(*conbuf == ESC)
    {
	abort_req = TRUE;
	return((long)ESC);
    }
    return(atoh(conbuf));   /* atoh will set error if bad digit */
} /* gethex (get string from console, translate into long) */


long atoh(buf)		    /* convert a buffer of up to 8 chars */
char *buf;		    /* from ascii string to long integer */
{
    long l = 0;
    register int i = 0;
    register int n;

    error = FALSE;
    while(*buf && (i++<8))
    {
	l *= 16;
	n = nibval(*buf++);
	if(n == -1)
	{
	    error = TRUE;
	    return(0);
	}
	l += n;
    }
    return(l);
} /* atoh */

/*page*/
nibval(nib)
char nib;
{
    nib = toupper(nib);
    if((nib >= '0') && (nib <= '9'))
	return(nib-'0');
    else if ((nib >= 'A') && (nib <= 'F'))
	return(nib-'A'+10);
    else
	return(-1);	    /* error */
}


sort(base,len,num)	 /* Sort table according to a 4-char field  (i.e. */
char *base;		 /* the upside-down serial number).  In reality   */
int len;		 /* the first two arguments are superfluous since */
int num;		 /* this sort ONLY works for the machine table.   */
{			 /* NOTE! -->  Entries with illegal product codes */
    int  gap, i;		    /* sort to the top regardless of serial. */
    register int j;
    char temp[sizeof(struct MTentry)];
    register char *cp1, *cp2;
    char prod1,prod2;

    for (gap = num/2; gap > 0; gap /=2) 	/* K & R's shell sort */
	for(i=gap; i < num; i++)
	    for(j=i-gap; j>=0; j-=gap)
	    {
		cp1 = base + (j*len);
		cp2 = base + ((j+gap) * len);
		prod1 = *(cp1+4);
		prod2 = *(cp2+4);

		if((chrcmp(cp2,cp1,4) >= 0) && prod1 && (prod1<MAX_PROD))
		    break;
		if(!(prod2 && (prod2<MAX_PROD)))
		    break;
		blockmv(temp,cp1,len);
		blockmv(cp1,cp2,len);
		blockmv(cp2,temp,len);
	    } /* reverse entries where necessary for one gap size */
	      /* (then outer loop for a given gap size) */
	      /* (outermost of three loops reduces gap size) */

} /* sort (sort table entries on an integer key) */

/*page*/
chrcmp(c1,c2,len)
char c1[],c2[];
int len;
{
    for(; len > 0; len--,c1++,c2++)
	if(*c1 != *c2)
	    return(*c1-*c2);
    return(0);
} /* compare character strings (nulls are nothing special) */


match(a,b,l)		/* tell if two strings are equal */
char *a, *b;
int l;
{
    return(chrcmp(a,b,l) == 0);
}

long_eq(x,y)
long x,y;
{
    return(match(&x,&y,4));
} /* compare two longs for equality; library routine .leq has a bug */

struct CONFIGURE *
mt_findmodel(p)
char *p;
{
    register int i;
    for(i=0;i < MAXDESC;++i) 
	if(!chrcmp(p,&(desc_code[i].prod),7))
	    return(&desc_code[i]);
    return(NULL);
} /* give pointer to configuration description of an mt entry */


mt_entries()		/* count the entries in the Machine Table */
{
    register struct MTentry *entry;
    register int i;

    entry = (struct MTentry *) machtable.buffer;
    for(i=0; (i<MAX_MACH) && (entry->product >0) &&
			     (entry->product <MAX_PRODS); ++i)
	++entry;
    return(i);
} /* count mt entries */


&& (entry->