/* **************************************************************************
 *									    *
 *		       Manage the System Directory			    *
 *			last updated 02/23/84 dsb			    *
 *									    *
 ************************************************************************** */

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

/* #define DBUG YES */

#define VERSION     1
#define REVISION    0
#define PATCH	    'b'

/* ************************ REVISION HISTORY ********************************
 *									    *
 *  0.0d    12/16/83	Marginally running before Dave's vacation           *
 *     e    01/05/84	Quick fix for Mike P.: return(0) instead of exit()  *
 *			 so any $$$.sub is not wiped out on a normal exit.  *
 *			 Exit(-1) is used if trying to run on a Master.     *
 *     f    01/15/84	Erase and Verify functions added		    *
 *			Find function (not in specs) removed		    *
 *     g    01/16/84	Fixed bug in Erase and one in List OS Table	    *
 *     h    01/17/84	Made error report like in specification.  Still no  *
 *			 general cross-reference; Modify does not query to  *
 *			 change every reference to changed name.  As .COM   *
 *			 file is now 50k I don't hold out much hope for     *
 *			 those features without radical changes.	    *
 *  0.1a    01/18/84	Radical changes.  Add/Modify, Erase, Verify and     *
 *			 Product Type routines are now overlays and the     *
 *			 functions needed by more than one overlay have     *
 *			 been consolidated into this module and utility     *
 *			 module SYSLIB5.				    *
 *     b    01/19/84	Made List an overlay.  Might as well be ruthless.   *
 *			Added settop() call in root to prevent disasters    *
 *     c    01/24/84	Big changes in Add/Modify:  Re-structured a bit,    *
 *			 added "replace" capability			    *
 *     d    01/24/84	Fixed various bugs in replace; made yorn() give     *
 *			 TRUE or FALSE instead of 'Y' or 'N'		    *
 *     e    01/25/84	More bugs in replace & add			    *
 *  0.2a    01/26/84	Getting ready for Beta release -- making sure user  *
 *			 interface agrees wiith document.		    *
 *			Add/Replace closes file before returning.	    *
 *  0.3a    02/10/84	Finds true size of Unit 0 rather than assuming 256k *
 *  1.0a    02/16/84	Fixed bug in add so it doesn't go ahead if not      *
 *			 enough room in Control Area			    *
 *			Load-list entry in Replace looks like Modify, not   *
 *			 Add -- you can keep existing settings		    *
 *			(Tested with new HARDIO.LIB which does its own	    *
 *			 T-H=- translation and deblocking for 8" disks)     *
 *     b    02/22/84	Fixed bugs in unit 0 size computation		    *
 ************************************************************************** */

/*page*/
/* ********************* COMPILATION/ LINKING INSTRUCTIONS ******************

Best is to set up a .SUB file with these commands:

; MAIN MODULE
czii -X2200 syslib.c
as syslib.asm
; ADD/REPLACE/MODIFY OVERLAY
czii -X2200 syslib1.c
as syslib1.asm
; ERASE OVERLAY
czii -X2200 syslib2.c
as syslib2.asm
; PRODUCT TABLE OVERLAY
czii -Z2100 syslib3.c
as syslib3.asm
; VERIFY OVERLAY
czii -X2200 syslib4.c
as syslib4.asm
; UTILITY MODULE
czii -X2200 syslib5.c
as syslib5.asm
; LIST OVERLAY				  /--- xfer.lib, which contains
czii -X2200 syslib6.c			 /     hardio.lib, will also work here.
as syslib6.asm				/
ln -tr syslib.o syslib5.o ovloader.o hardio.lib libc.lib
ln -t syslib1.o syslib.rsm ovbgn.o libc.lib
ln -t syslib2.o syslib.rsm ovbgn.o libc.lib    (the -t switch is only needed
ln -t syslib3.o syslib.rsm ovbgn.o libc.lib	if you want a .SYM file for
ln -t syslib4.o syslib.rsm ovbgn.o libc.lib	use in debugging)
ln -t syslib6.o syslib.rsm ovbgn.o libc.lib
sidsym syslib.sym syslib.sid			(these are only needed if
sidsym syslib1.sym syslib1.sid			 you want to use SID)
sidsym syslib2.sym syslib2.sid
sidsym syslib3.sym syslib3.sid
sidsym syslib4.sym syslib4.sid
sidsym syslib6.sym syslib6.sid

*************************************************************************** */
/*page*/
#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 SDtrack   0x02		/* constants describing location and length */
#define SDsector  0x09		/* of tables on hard disk unit 0 */
#define SDlength    24

#define OSTtrack  0x01
#define OSTsector 0x21
#define OSTlength   96

#define PTtrack   0x01
#define PTsector  0x19
#define PTlength     8

#define ALtrack   0x00
#define ALsector  0x79
#define ALlength     1		/* only one sector of alloc table is read */

#define MAX_UNIT_0  512 	/* 512k is maximum size here. */

#define ADDING	     'A'
#define MODIFYING    'M'
 
#define E_OVSMALL	-5
#define E_NOMEM 	-6
#define E_NOTOVLY	-7

extern int errno;
/* ************************* C MACROS **************************** */

#define getfile(f)	  hd_xfer(READ,f.track,f.sector,f.buffer,f.length)
#define putfile(f)	  hd_xfer(WRITE,f.track,f.sector,f.buffer,f.length)
#define pf printf

/*page*/
/* ************************ 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;

struct SDentry {
    char name[8];   /* file name */
    char volume;    /* disk address */
    char unit;
    int  track;
    char sector;
    int  length;    /* number of 128-byte records */
    long load_addr; /* load address in host memory */
    int  exec_off;  /* offset from there to start of code */
    char prog_flag; /* program/data flag (not currently used) */
    char reserved[2];
    };

struct OSTentry {
    char os;
    char prod_map[16];
    char opt_map[6];
    char load_list[8][8];
    int  length;
    char reserved[7];
    };

struct PTentry {
    char type;
    char bp2_name[8];
    char lgn_name[8];
    char osm_name[8];
    };

/*page*/
char *product[] = {
    "Impossible Product",
    "ZSBC-3 Computers",
    "DSC-4",
    "DMS-1280",
    "DMS-3/C \"Killer Bee\"",
    "DMS-86 and DMS-5086",
    "DMS-5016",
    "DMS-816"
    };


char SDbuf[24*128];	/* buffer for System Directory */
char OSTbuf[96*64];	/* buffer for OS Tab
e CUT IN HALF TO MAKE ROOM */
char PTbuf[1024];	/* buffer for Product Type Table */
int error = FALSE;
int abort_req = FALSE;
int unit_0_k;

SFILE sysdir = {
    SDtrack,
    SDsector,
    SDlength,
    SDbuf
    };

SFILE ostable = {
    OSTtrack,
    OSTsector,
    OSTlength/2,	    /* NOTE CUT-DOWN LENGTH TO SAVE MEMORY */
    OSTbuf
    };

SFILE prodtable = {
    PTtrack,
    PTsector,
    PTlength,
    PTbuf
    };

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

long atoh(),gethex();

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

main()
{
    int i,j;

    settop(0x3000);	    /* at least as large as largest overlay */
 
    printf("\n\n     SYSLIB %d.%d%c-- Maintain the System File Directory", 
	    VERSION,REVISION,PATCH);

    check_mast();

    if(!hd_init())	    /* prepare hard disk to be talked to */
    {
	printf("\nHard disk not operational.");
	bye();
    }

    unit_0_k = get_u0_size();	/* find out how big unit 0 is */

#ifdef DBUG
    printf("\nunit_0_k = 0x%x",unit_0_k);
#endif


    getfile(sysdir);		/* getfile is a macro and operates on */
    getfile(ostable);		/* structures, not pointers to them */
    getfile(prodtable);

    for ever
    {
	i = menu();
	switch(i)
	{
	    case 'Q':		
	    case 0x03:	bye();			      /* exit to CP/M	*/
	    case 'A':	ovlay("SYSLIB1",ADDING);    /* add a new file  */
			break;
	    case 'M':	ovlay("SYSLIB1",MODIFYING); /* modify an entry */
			break;
	    case 'E':	ovlay("SYSLIB2",0);	    /* erase a file   */
			break;
	    case 'V':	ovlay("SYSLIB4",0);	   /* check for problems */
			break;
	    case 'P':	ovlay("SYSLIB3",0);	/* Product Table sub-menu */
			break;
	    case 'L':	ovlay("SYSLIB6",0);	   /* listing sub-menu */
			break;
	}
    } /* loop until exit requested */
} /* main */

ovlay(name,arg) 	/* Call an overlay.  We get to pass one arg to it. */
char *name;
int arg;
{
    int i;

    errno = 0;
    if((i=ovloader(name,arg)) == -1)	/*  -1 return means error */
    {
	printf("\nError (%d) in loading overlay %s.OVR: ",errno,name);
	switch(errno)
	{
	    default:	    printf("overlay file missing?");
			    break;
	    case E_NOMEM:   printf("not enough memory to load it!");
			    break;
	    case E_OVSMALL: printf("overlay appears corrupted");
			    break;
	    case E_NOTOVLY: printf("file is not an overlay");
			    break;
	    case 0:	    printf("cannot find it");
			    break;
	}  /* switch on errno */
    } /* if -1 return from ovloader */
    return(i);
} /* ovlay */


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

/*page*/						    

check_mast()
{
    char *usernum;
    usernum = (char *) 0x47;

    if(!*usernum)
    {
	printf("\nThis program will not work on a running Master.");
	printf("\nYou can run SYSLIB if you boot from a floppy.");
	exit(-1);	/* error */
    }

    if(*usernum != 0xFF)
    {
	printf("\n\nYou are running this program on a network station.");
	printf("\nSYSLIB 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.");
	wait_user();
    }
}



menu()
{
    char choice;

    do
    {
    pf("\nSYSLIB MAIN MENU");
    pf("\n");
    pf("\n  A  -  ADD/REPLACE   Add or replace a Control Area Directory file");
    pf("\n  E  -  ERASE         Erase a file from the Control Area Directory");
    pf("\n  M  -  MODIFY        Change a Control Area file name");
    pf("\n");
    pf("\n  L  -  LIST          Display Control Area Directory or OS List");
    pf("\n  V  -  VERIFY        Verify that the Control Area is complete");
    pf("\n");
    pf("\n  P  -  PRODUCT       Modify the Product Table");
    pf("\n");
    pf("\n  Q  -  QUIT          Leave this program.");
    pf("\n");
    pf("\nEnter your choice --> ");
    } while (dgets(&choice,1) != 1);
    return(toupper(choice));
}

/*page*/

struct SDentry *
find_sd(name)
char *name;
{
    struct SDentry *sd_ent;

    sd_ent = (struct SDentry *) sysdir.buffer;
    while((sd_ent->name[0]) && (strncmp(sd_ent->name, name,8)))
	sd_ent++;

    if(sd_ent->name[0] == '\0')
	return(NULL);

    return(sd_ent);
} /* find sys dir entry by name */


struct OSTentry *
find_os(name)
char *name;
{
    struct OSTentry *ent;

    ent = (struct OSTentry *) ostable.buffer;
    while((ent->load_list[0][0]) && (strncmp(ent->load_list, name,8)))
	ent++;

    if(ent->load_list[0][0] == '\0')
	return(NULL);

    return(ent);
} /* find os table entry by name */



sd_entries()	    /* return the number of entries in the sys dir */
{
    struct SDentry *sd_ent;
    unsigned a;
    int i = 0;

    sd_ent = (struct SDentry *) sysdir.buffer;
    while((a=sd_ent->name[0]) && (a != 0xE5))
    {
	sd_ent++;		/* go to end */
	i++;
    }
    return(i);
} /* sd_entries */

/*page*/
ost_entries()	     /* return the number of entries in the OS table */
{
    struct OSTentry *ost_ent;
    unsigned a;
    int i = 0;

    ost_ent = (struct OSTentry *) ostable.buffer;
    while((a=ost_ent->load_list[0][0]) && (a != 0xE5))
    {
	ost_ent++;		 /* go to end */
	i++;
    }
    return(i);
} /* ost_entries */




its_an_os(buf)		/*  see whether a file has an OS header  */
char *buf;
{
    char *ref = "THIS IS A HEADER";	/* unambiguous clue */
    if(strncmp(ref,buf+25,strlen(ref)))
	return(FALSE);
    else
	return(TRUE);
}

get_u0_size()		/* figure out the real size of Unit 0 */
{
    char ALbuf[128];
    SFILE alloctab;
    register char size;
    register unsigned k;
    register int bad = FALSE;

    alloctab.track = ALtrack;
    alloctab.sector = ALsector;
    alloctab.length = ALlength;
    alloctab.buffer = ALbuf;

    getfile(alloctab);	/* now first byte conveniently tells size */
    size = *ALbuf;

    if(size < 0)
	bad = TRUE;

#ifdef DBUG
    printf("\n*DBUG* partition 0 size byte is %02x",size);
#endif

    for(k=128; size; --size)
	k *= 2;

#ifdef DBUG
    printf("\n*DBUG* that works out to %dk (decimal)",k);
#endif

    if((k < 256) || (k > MAX_UNIT_0))
	bad = TRUE;

    if(bad)
    {
	printf("\n\nError - the size of your Control Area is listed as %dk.",
		    k);
	printf("\nSYSLIB only understands sizes of 256k or 512k for the ");
	printf("Control Area.\n");
	exit(-1);
    }

    return(k);
} /* get Unit 0 size */

izes of 256k or 512k for the ");
	printf("Cont