/* *******************************************************************
 *								     *
 *		     Manage the Machine Table			     *
 *		     last updated 02/23/84 dsb			     *
 *								     *
 ******************************************************************* */

/* #define DBUG 1  */

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

#define VERSION     1
#define REVISION    1
#define PATCH	    'f'

/* *********************** REVISION HISTORY ****************************

1.0a	12/19/83    First try.	Only "normal" machines can be added to the
		    table - customized ones such as Foxes with 8-inch floppies
		    cannot be added.

   b	01/05/84    HNS-86's have printers now
		    The three "other" bits of iobyte default correctly
		    Ok to re-enter same serial number when modifying
		    Serial number comparisons use long_eq() rather than
		     the built-in .leq which doesn't always work

   c	01/09/84    Rearrange structures relating to IOBYTE to allow
		     different products to have different physical
		     devices represented by the same logical device

   d	01/16/84    Fix up some option maps
   e	01/17/84    exit(0)
   f	01/18/84    Fix up menu messages
   g	01/26/84    Fix up just a bit more for beta release
   h	01/27/84    Changed option maps to give 86's & 816's 8 drives
   i	01/30/84    Changed option maps to agree w/2.247d9 release
   j	02/06/84    Changed them back -- Foxes, 15's and 5080's are to
		     have polled port 0's.  Patch i resulted from a
		     BIOS bug after all.
1.1a	02/07/84    Works on running Master -- calls data_xfer() instead
		     of hd_xfer(); uses library xfer.lib instead of
		     hardio.lib
   b	02/08/84    Magic numbers changed so sectors start at 0, not 1,
		     as data_xfer does it that way
		    Check for invalid user numbers
   c	02/08/84    Fixed user number check bug
   d	02/21/84    Fixed upper limit on number of entries (128, not 40)
		     in add/modify
		    #includes machine.h, not xmachine.h as it incorrectly
		     had since 1.1a
   e	02/22/84    Same upper-limit fix for mt_entries()
		    Fixed machine.h to be just same as old xmachine.h
		    Put some variables in registers
		    Moved mt_findmodel(), mt_entries() to MACHINE3
   f	02/23/84    Took out COMDEX machine selection

*/
/*page*/
/* ************************* MISCELLANEOUS EQUATES ***********************  */

#define ever	    (;;)
#define FALSE	    0
#define TRUE	    1
#define CR	    0x0D
#define BS	    0x08
#define DEL	    0x7F
#define ESC	    0x1B
#define CTRL_X	    'X'-'@'
#define ADDING	    'A'
#define MODIFYING   'M'

#define MAX_PROD    20		/* all we expect */
#define MAX_MACH    128

#define MTtrack   0x01		/* Location and length of table in Unit 0 */
#define MTsector  0x08		/* 8 is LOGICAL sector (phys. sect is 9) */
#define MTlength    12

/* ********************* OPTION MAP BIT LABELS ******************* */ 
			/*  3	3B  3F	10x 15	5080
#define OP_8FLOP    0	/*  1	0   0	1   0	0	    */
#define OP_FOXFLOP  1	/*  0	0   1	0   1	0	    */
#define OP_IBMFLOP  2	/*  0	0   0	0   0	0	    */
#define OP_8HARD    3	/*  0	0   0	1   0	0	    */
#define OP_XEBHARD  4	/*  0	0   0	0   1	0	    */
#define OP_ADPHARD  5	/*  0	0   0	0   0	0	    */
#define OP_P0AHEAD  6	/*  1	1   0	1   0	0	    */
#define OP_P0POLL   7	/*  0	0   1	0   1	1	    */

#define OP_P2POLL   8	/*  1	1   1	1   1	1	    */
#define OP_P3AHEAD  9	/*  1	1   1	1   1	1	    */
#define OP_P3POLL   10	/*  0	0   0	0   0	0	    */
#define OP_PAR1CON  11	/*  1	1   1	1   1	1	    */
#define OP_PAR1PRT  12	/*  1	1   1	1   1	1	    */
#define OP_PAR2PRT  13	/*  1	1   1	1   1	0	    */
#define OP_PRTMUX   14	/*  1	1   1	1   1	1	    */
#define OP_SPOOLER  15	/*  1	1   1	1   1	1	    */

#define OP_NETBUFF  16	/*  1	1   1	1   1	1	    */
#define OP_CLOCK    17	/*  1	1   1	1   1	1	    */
#define OP_FRONTINT 18	/*  1	1   1	1   1	1	    */
#define OP_DRIVES   19	  /* also uses 20,21,22 for number of logical drives */
#define OP_MEMMAP   23	  /* brand new memory-mapped console on 816 */

/* ************************* C MACROS **************************** */

#define getfile(f)     data_xfer(READ,f.track,f.sector,f.buffer,f.length)
#define putfile(f)     data_xfer(WRITE,f.track,f.sector,f.buffer,f.length)

/* ****************** MISCELLANEOUS GLOBAL STORAGE *************** */

char MTbuf[12*128];	/* buffer for System Directory */
int error = FALSE;
int abort_req = FALSE;

/* ************************ STRUCTURES *************************** */

typedef struct sfile {		/* table description */
    int track;		/* beginning track   */
    char sector;	/* beginning sector  */
    char length;	/* number of sectors */
    char *buffer;	/* buffer it goes in */
    } SFILE;

SFILE machtable = {
    MTtrack,
    MTsector,
    MTlength,
    MTbuf
    };

struct MTentry {
    long sernum; 
    char product;
    char optmap[6];
    char iobyte;
    };

/*page*/
#define MAXDESC 15
struct CONFIGURE {
    char prod;
    char optm[6];
    char def_iob;
    char *short_name;
    char *long_name;
    char *description;
    };

struct CONFIGURE desc_code [MAXDESC] = {
    1, 0x41,0xFB,0x27, 0,0,0, 0x54, "3",    "DMS-3","dual 8\" floppies",
    1, 0x49,0xFB,0x27, 0,0,0, 0x54, "3/10X","DMS-3/10x","8\" hard disk",
    1, 0x94,0xDB,0x27, 0,0,0, 0x5E, "3/501","DMS-3/501",
					  "5\" hard disk, IBM-style floppies",
    1, 0x40,0xC0,0x27, 0,0,0, 0x00, "3/A25","DMS-3/A25",
						    "\"Smart ADDS Terminal\"",
    1, 0x40,0xFB,0x27, 0,0,0, 0x54, "3/B",  "DMS-3/B",NULL,
    4, 0x00,0x00,0x08, 0,0,0, 0x54, "3/C",  "DMS-3/C","\"Killer Bee\"",
    1, 0x82,0xFB,0x27, 0,0,0, 0x56, "3/F",  "DMS-3/F","\"Fox\"",
    1, 0x92,0xDB,0x27, 0,0,0, 0x5E, "15",   "DMS-15",
						   "5\" hard disk, 5\" floppy",
    2, 0x41,0xFB,0x27, 0,0,0, 0x54, "4",    "DMS-4",   NULL,
    5, 0x40,0xDB,0x47, 0,0,0, 0x54, "86",   "DMS-86",  NULL,
    7, 0x40,0xA1,0xC1, 0,0,0, 0x54, "816",  "DMS-816" ,NULL,
    3, 0x40,0xC0,0x27, 0,0,0, 0x00, "1280", "DMS-1280",NULL,
    6, 0x40,0xFB,0x47, 0,0,0, 0x56, "5016", "DMS-5016",NULL,
    1, 0x80,0xFB,0x27, 0,0,0, 0x56, "5080", "DMS-5080",NULL,
    5, 0x40,0xFB,0x47, 0,0,0, 0x56, "5086", "DMS-5086",NULL,
    };				   
char *oddconfig = "(CUSTOM)    ";
/*page*/
/* ******** Structures to allow description of available i/o devices ******* */

struct PORT {			    /* names of physical io facilities in */
    char *shorter;		    /* abbreviated and full form, and the */
    char *longer;		    /* bits in the bit-map which say whether */
    char map1;			    /* you have one (maybe two such bits, eg.*/
    char map2;			    /* typeahead & poll, console & printer..)*/
    };				    /* Test on bit 0xFF always returns FALSE */

struct IOFEATURES {	  /* types of logical-to-physical correspondence */
    struct PORT *con[4];  /* (not as many of these as there are products */
    struct PORT *prt[8];  /* since nearly everything looks like a DSC-3) */
    };

struct PRODUCT {	    /* for a given product number, there is a struct */
    char *name; 	    /* of this type which gives its name and points */
    struct IOFEATURES *io;  /* to a description of its io facilities */
    };

struct PORT port[] = {
    "SERIAL 0  ","Serial Port 0",   OP_P0AHEAD, OP_P0POLL,    /* 0 */
    "SERIAL 2  ","Serial Port 2",   OP_P2POLL,	0xFF,	      /* 1 */
    "PARALLEL 1","Parallel Port 1", OP_PAR1CON, OP_PAR1PRT,   /* 2 */
    "SERIAL 3  ","Serial Port 3",   OP_P3AHEAD, OP_P3POLL,    /* 3 */
    "NOTHING   ","Invalid device",  0xFF, 0xFF, 	      /* 4 */
    "PARALLEL 2","Parallel Port 2", OP_PAR2PRT, 0xFF,	      /* 5 */
    "CUSTOM    ","Custom Printer",  OP_P2POLL,	0xFF,	      /* 6 */
    "SPOOLER   ","Spooler",	    OP_SPOOLER, 0xFF,	      /* 7 */
    "MEMORY MAP","Built-in Monitor",OP_MEMMAP,	0xFF, /* 8- new with 816 */
    "816 SERIAL","816 Serial Port", OP_P2POLL,	0xFF,
    "816 PAR'L ","816 Parallel Port",OP_PAR1PRT, 0xFF
    };

struct IOFEATURES io_devs[] = {
    &port[0],&port[1],&port[2],&port[3],    /* arrangement for most products */
    &port[0],&port[3],&port[1],&port[4],&port[2],&port[5],&port[6],&port[7],
    &port[8],&port[4],&port[4],&port[4],    /* arrangement for the 816 */
    &port[4],&port[4],&port[9],&port[4],&port[4],&port[4],&port[4],&port[7]
    };

char *cpm_console[] = {
    "TTY:", "CRT:", "BAT:", "UC1:"
    };

char *cpm_printer[] = {
    "TTY:", NULL, "CRT:", NULL, "LPT:", NULL, "UL1:", NULL
    };

/*page*/

char *option[] = {
    "8\" floppies",
    "5\" floppies (Fox-style)",
    "5\" floppies (IBM-style)",
    "8\" hard disk",
    "5\" hard disk (Xebec controller)",
    "5\" hard disk (Adaptec controller)",
    "Port 0 type-ahead console",
    "Port 0 polled console",
    "Port 2 printer",
    "Port 3 type-ahead comm. port",
    "Port 3 polled comm. port",
    "Parallel Port 1 Console",
    "Parallel Port 1 Printer",
    "Parallel Port 2 Printer",
    "Printer on Console AUX port",
    "Spooler",
    "1k Net Buffer",
    "Real-Time Clock",
    "Front-Panel Interrupt"
    };

struct PRODUCT product[] = {
    "Impossible Product",NULL,
    "ZSBC-3 Computers",&io_devs[0],
    "DSC-4",	       &io_devs[0],
    "DMS-1280",        &io_devs[0],
    "DMS-3/C \"Killer Bee\"",&io_devs[0],
    "DMS-86 and DMS-5086",   &io_devs[0],
    "DMS-5016", 	     &io_devs[0],
    "DMS-816 ", 	     &io_devs[1] 
    };


/* ********************* FUNCTIONS THAT DON'T RETURN INTS **************** */

long atoh(),gethex();

/*page*/
/* ************************* MAIN BODY ********************************** */

main()
{
    int i;

    printf("\n\n\t\tMACHINE %d.%d%c-- Maintain the Machine Table\n", 
	    VERSION,REVISION,PATCH);

    check_user();	     /* notice what type of user we are */

    if(!getfile(machtable))
    {
	printf("\nHard disk not operational.");
	bye();
    }

    for ever
    {
	i = menu();
	switch(i)
	{
	    case 'Q':		
	    case 0x03:	bye();
	    case 'A':	mt_a_m(ADDING);
			break;
	    case 'C':	mt_a_m(MODIFYING);
			break;
	    case 'D':	mt_delete();
			break;		     
	    case 'L':	list(); 
			break;
       /*   case 'F':	find();
			break;	*/
	}
    } /* loop until exit requested */
} /* main */

zabort()
{
    printf("\n\nExiting ignominiously to CP/M\n");
    exit(-1);
}

bye()
{
    printf("\n\nExiting to CP/M\n");
    exit(0);
}



/*page*/
check_user()
{
    register char *usernum;
    register char unum;

    usernum = (char *) 0x47;
    if((unum = *usernum) == 0xFF)	/* single user, ok */
	return();

    else if(!unum)			/* Master, print warning */
    {
	printf("\nThis is a running HiNet Master.");
	if(users_in())
	{
	    printf("\nThere are users currently logged in!  To avoid confu");
	    printf("sing\nthem, do not modify any existing Machine Table ");
	    printf("entries\nwithout telling the users of the affected mach");
	    printf("ines.\nYou may add NEW entries, which will not affect");
	    printf(" existing users.");
	    wait_user();
	}
	else
	    printf("  No other users are currently logged in.");
    }

    else if(unum & ~31) 	      /* Illegal user number */
    {
	printf("\n\07Something is wrong.  Your user number of %x (hex)",
		unum);
	printf("\n is not a valid number.  Attempting to exit program:\n");
	exit(-1);
    }

    else				/* must be a HiNet station */
    {
	printf("\n\nYou are running this program on a network station.");
	printf("\nMACHINE will read and write the tables from the LOCAL hard");
	printf(" disk attached to\nthis station.  If you intended to work on");
	printf(" the SHARED hard disk attached to\nthe Master, you should ");
	printf(" abort this program now, and go to the Master to run it.");
	wait_user();
    }
} /* check_mast */

users_in()	    /* see if there are other users in */
{
    char *usertable = 0xFC00;
    int i;

    for(i=1; i<32; ++i)
    {
	usertable +=16; 	/* start w/entry 1, not 0 */
	if(*usertable)		/* anything above 0 will do */
	    return(TRUE);
    }
    return(FALSE);
} /* see if there ae users in */


menu()
{
    char choice;

    do
    {
    printf("\n\n\nMACHINE MAIN MENU");
    printf("\n");
    printf("\n  A  -  ADD       Add an entry to the Machine Table.");
    printf("\n  C  -  CHANGE    Change an entry in the Machine Table.");
    printf("\n  D  -  DELETE    Delete an entry from the Machine Table.");
    printf("\n  L  -  LIST      Display the Machine Table.");
    printf("\n  Q  -  QUIT      Leave this program.");
    printf("\n");
    printf("\nEnter your choice --> ");
    } while (dgets(&choice,1) != 1);
    return(toupper(choice));
}


list()	    
{
    register struct MTentry *entry;
    register int i;

    printf("\n\n     MACHINE TABLE\n");
    mt_header();
    entry = (struct MTentry *) machtable.buffer;
    for(i=0; entry->product && (entry->product < 10) && (i < 128); i++,entry++)
    {
	mt_prt(entry);
	check_wait();
    }
    printf("\n");
    waitkey();
} /* dump table */
/*page*/


mt_header()
{
    printf("\nSerial #   Model          Console      Printer");
    printf("\n--------   -----          -------      -------");
    return(); 
} /* print header for machine table list */


mt_prt(ent)			/* horizontal print for listing */
struct MTentry *ent;
{
    return(mt_prt_2_ways(ent,FALSE));
}


mt_prt_vert(ent)		/* vertical print for confirmation */
struct MTentry *ent;
{
    return(mt_prt_2_ways(ent,TRUE));
}

/*page*/
mt_prt_2_ways(ent,vert) 	/* vertical or hzontal */
struct MTentry *ent;
int vert;
{
    register int i;
    register struct CONFIGURE *x;
    register struct IOFEATURES *iop;
    char *p,*p2;

    iop = product[ent->product].io;

    printf("\n");
    if(vert)
	printf("\nSERIAL #: \t");
    p = (char *) &ent->sernum;
    for(i=0; i<4; i++)
	printf("%02x",*p++);

    if(vert)
	printf("\nMODEL:  \t");
    else
	printf("   ");

    printf("%-15s",mt_describe(&(ent->product)));

    x = mt_findmodel(&(ent->product));

    if(vert)
	printf("\nCONSOLE: \t");
    i = ent->iobyte & 0x03;
    if((x != NULL) && (i == (x->def_iob & 0x03)))
	printf("STANDARD     ");
    else
	printf("%-13s",iop->con[i]->shorter);
    if(vert)
	printf("\nPRINTER: \t");
    i = (ent->iobyte >> 5) & 0x07;
    if((x != NULL) && (i == ((x->def_iob >>5) & 0x07)))
	printf("STANDARD     ");
    else
	printf("%-13s",iop->prt[i]->shorter);

    return();
} /* print an mt entry (horizontal or vertical) */

/*page*/

mt_describe(p)
char *p;
{
    register struct CONFIGURE *x;

    if((x = mt_findmodel(p)) != NULL)
	return(x->long_name);
    else  
	return(oddconfig);
} /* return pointer to long name of model */

mt_delete()
{
    long serial;
    struct MTentry *ent;
    int entries;

    printf("\nEnter serial number of machine you wish to delete. ");
    printf("\nPress ESC to go back to main menu) --> ");
    get_serial(&serial,FALSE);	     /* default not ok here */
    if(abort_req)
	return();
    if((ent=mt_find(serial)) == NULL)
    {
	printf("\n\07That machine is not in the table. ");
	return();
    }

    printf("\nYou have asked to delete this machine:");
    mt_prt_vert(ent);
    if(!is_correct())
	return();

    entries = mt_entries();
    clear(ent,sizeof(struct MTentry),'\0');  /* 0 is an illegal product code */
					     /* so this entry will be sorted */
					     /* out to the end. */
    sort(machtable.buffer,sizeof(struct MTentry),entries);
    putfile(machtable);
    return();
} /* delete */

end. */
    sort(machtable.buffer,sizeof(struct MTentry),entries);
