mirror of
https://github.com/SEPPDROID/Digital-Research-Source-Code.git
synced 2025-10-25 01:14:21 +00:00
747 lines
24 KiB
C
747 lines
24 KiB
C
/***************************************************************/
|
||
/***************************************************************/
|
||
/* genc2.c: more genccpm.cc, broken up for shorter compiles */
|
||
/***************************************************************/
|
||
/***************************************************************/
|
||
#ifndef MAINMODULE
|
||
#include <genccpm.h>
|
||
#endif
|
||
|
||
|
||
/**************************************************************************/
|
||
/* init_sds: points the system data pointers to the right place
|
||
/**************************************************************************/
|
||
VOID
|
||
init_sds(sysdat)
|
||
BYTE *sysdat; /* ptr to system data buffer */
|
||
{
|
||
sd_supmod = sysdat + 0x00; /* (4) */
|
||
sd_rtmmod = sysdat + 0x08; /* (4) */
|
||
sd_memmod = sysdat + 0x10; /* (4) */
|
||
sd_ciomod = sysdat + 0x18; /* (4) */
|
||
sd_bdosmod = sysdat + 0x20; /* (4) */
|
||
sd_xiosmod = sysdat + 0x28; /* (4) */
|
||
sd_netmod = sysdat + 0x30; /* (4) */
|
||
sd_mpmseg = sysdat + 0x40;
|
||
sd_rspseg = sysdat + 0x42;
|
||
sd_endseg = sysdat + 0x44;
|
||
sd_module_map = sysdat + 0x46;
|
||
sd_ncns = sysdat + 0x47;
|
||
sd_nlst = sysdat + 0x48;
|
||
sd_nccb = sysdat + 0x49;
|
||
sd_nflags = sysdat + 0x4A;
|
||
sd_srchdisk = sysdat + 0x4B;
|
||
sd_mmp = sysdat + 0x4C;
|
||
sd_nslaves = sysdat + 0x4E;
|
||
sd_dayfile = sysdat + 0x4F;
|
||
sd_tempdisk = sysdat + 0x50;
|
||
sd_tickspsec = sysdat + 0x51;
|
||
sd_lul = sysdat + 0x52;
|
||
sd_ccb = sysdat + 0x54;
|
||
sd_flags = sysdat + 0x56;
|
||
sd_mdul = sysdat + 0x58;
|
||
sd_nxmds = sysdat + 0x58;
|
||
sd_mfl = sysdat + 0x5A;
|
||
sd_nmparts = sysdat + 0x5A;
|
||
sd_pul = sysdat + 0x5C;
|
||
sd_nxpd = sysdat + 0x5C;
|
||
sd_qul = sysdat + 0x5E;
|
||
sd_nqds = sysdat + 0x5D;
|
||
sd_qmau = sysdat + 0x60; /* (4) */
|
||
sd_qmastart = sysdat + 0x62;
|
||
sd_qmalen = sysdat + 0x64;
|
||
sd_verptr = sysdat + 0x78;
|
||
sd_vn = sysdat + 0x7A;
|
||
sd_mpmvn = sysdat + 0x7C;
|
||
sd_ncondev = sysdat + 0x83;
|
||
sd_nlstdev = sysdat + 0x84;
|
||
sd_nciodev = sysdat + 0x85;
|
||
sd_lcb = sysdat + 0x86;
|
||
sd_popen_max = sysdat + 0x8A;
|
||
sd_plock_max = sysdat + 0x8B;
|
||
sd_cmode = sysdat + 0x90;
|
||
sd_xpcns = sysdat + 0x9f;
|
||
}
|
||
|
||
|
||
/************************************************************************/
|
||
/* doxios: gets miscellaneous XIOS values from user */
|
||
/************************************************************************/
|
||
BYTE *
|
||
doxios(bb,xmtitle) /* submenu for XIOS value mods */
|
||
BYTE *bb; /* value passed in from menu */
|
||
BYTE *xmtitle;
|
||
{
|
||
BYTE cmds[CMDSLEN]; /* space for additional commands */
|
||
EXTERN BYTE *clearit;
|
||
|
||
if( bb != NULLPTR ) { /* if any "command line" arguments */
|
||
domenu(bb); /* do what they've asked for */
|
||
} else FOREVER { /* work with user for a while */
|
||
printf("%s",clearit); /* clear screen */
|
||
prtmenu(xmtitle); /* display user options */
|
||
printf(PROMPT); /* prompt user */
|
||
if( gets(cmds)!=cmds || /* on end of file */
|
||
*cmds==NULL ) /* or blank line of input */
|
||
break; /* exit interaction with user */
|
||
domenu(cmds); /* do what they've asked for */
|
||
} /*****************************/
|
||
return NULLPTR; /* standard return... */
|
||
}
|
||
|
||
|
||
|
||
/************************************************************************/
|
||
/* dosysp: gets miscellaneous system paramaters from user */
|
||
/************************************************************************/
|
||
BYTE *
|
||
dosysp(bb,smtitle) /* submenu for SYSP value mods */
|
||
BYTE *bb; /* value passed in from menu */
|
||
BYTE *smtitle;
|
||
{
|
||
BYTE cmds[CMDSLEN]; /* space for additional commands */
|
||
EXTERN MENU *syspmenu; /* list of menu items for sysp menu */
|
||
EXTERN BYTE *clearit;
|
||
|
||
if( bb != NULLPTR ) { /* if any "command line" arguments */
|
||
domenu(bb,syspmenu); /* do what they've asked for */
|
||
} else FOREVER { /* work with user for a while */
|
||
printf("%s",clearit); /* clear screen */
|
||
prtmenu(smtitle,syspmenu); /* display user options */
|
||
printf(PROMPT); /* prompt user */
|
||
if( gets(cmds)!=cmds || /* on end of file */
|
||
*cmds==NULL ) /* or blank line of input */
|
||
break; /* exit interaction with user */
|
||
domenu(cmds,syspmenu); /* do what they've asked for */
|
||
} /*****************************/
|
||
return NULLPTR; /* standard return... */
|
||
}
|
||
|
||
|
||
|
||
/*************************************************************************/
|
||
/* dorsp: handles rsp editting */
|
||
/*************************************************************************/
|
||
BYTE *
|
||
dorsp(parm,xmtitle) /* handle RSP list editting */
|
||
BYTE *parm; /* command value parameter */
|
||
BYTE *xmtitle;
|
||
{
|
||
BYTE cmds[CMDSLEN]; /* space for additional commands */
|
||
EXTERN MENU *rspmenu; /* list of menu items for rsp menu */
|
||
EXTERN BYTE *clearit;
|
||
|
||
if( parm != NULLPTR ) { /* if any "command line" arguments */
|
||
domenu(parm,rspmenu); /* do what they've asked for */
|
||
} else FOREVER { /* work with user for a while */
|
||
printf("%s",clearit); /* clear screen */
|
||
rsp_display(rsps); /* display what they have to work with */
|
||
prtmenu(xmtitle,rspmenu); /* display user options */
|
||
printf(PROMPT); /* prompt user */
|
||
if( gets(cmds)!=cmds || /* on end of file */
|
||
*cmds==NULL ) /* or blank line of input */
|
||
break; /* exit interaction with user */
|
||
domenu(cmds,rspmenu); /* do what they've asked for */
|
||
} /*****************************/
|
||
return NULLPTR; /* standard return... */
|
||
}
|
||
|
||
/*************************************************************************/
|
||
BYTE *
|
||
rspinclude(rs)
|
||
BYTE *rs;
|
||
{
|
||
BYTE *bp, *cp, *ep; /* ptrs to take apart command str */
|
||
DLIST *dd;
|
||
|
||
if( rs==NULLPTR || *rs==NULL )
|
||
return "You need to say 'include=xx.rsp,yy.rsp,zz.rsp'";
|
||
for( ep=rs; *ep; ++ep ) ; /* end of string pointer */
|
||
for( bp=rs; bp<ep; bp=cp+1 ){ /* process each rsp spec */
|
||
for( cp=bp; *cp && *cp!=','; ++cp ) ; /* find eos or comma */
|
||
if( *cp == ',' ) *cp = '\0'; /* null terminate the spec */
|
||
if( (dd=dirsearch(bp)) == NULLPTR )
|
||
return "Can't find RSP to include";
|
||
rspjoin(dd);
|
||
}
|
||
return NULLPTR;
|
||
}
|
||
|
||
rspjoin(dd)
|
||
DLIST *dd;
|
||
{
|
||
DLIST *rs;
|
||
|
||
if( rsps == NULLPTR )
|
||
rsps = dd;
|
||
else {
|
||
for( rs=rsps; rs->dlnext != NULLPTR; rs=rs->dlnext ) ;
|
||
rs->dlnext = dd;
|
||
}
|
||
}
|
||
|
||
|
||
|
||
/*************************************************************************/
|
||
BYTE *
|
||
rspexclude(rs)
|
||
BYTE *rs;
|
||
{
|
||
BYTE *bp, *cp, *ep;
|
||
BOOLEAN rspzap();
|
||
|
||
if( rs==NULLPTR || *rs==NULL )
|
||
return "You need to say 'exclude=aa.rsp,bb.rsp,cc.rsp'";
|
||
for( ep=rs; *ep; ++ep ) ; /* find eos */
|
||
for( bp=rs; bp<ep; bp=cp+1 ){ /* process each rsp spec */
|
||
for( cp=bp; *cp && *cp!=','; ++cp ) ; /* find eos or comma */
|
||
if( *cp == ',' ) *cp = '\0'; /* null terminate the spec */
|
||
if( !rspzap(bp) )
|
||
return "Can't find RSP to exclude";
|
||
}
|
||
return NULLPTR;
|
||
}
|
||
|
||
BOOLEAN
|
||
rspzap(nm)
|
||
BYTE *nm;
|
||
{
|
||
DLIST **qs, *ps, *rs;
|
||
|
||
if( *nm == '*' ) { /* zap entire list? */
|
||
for( ps=rsps; ps!=NULLPTR; ps=rs ) {
|
||
rs = ps->dlnext;
|
||
free(ps);
|
||
}
|
||
rsps = NULLPTR;
|
||
return TRUE;
|
||
}
|
||
for( qs= &rsps; *qs!=NULLPTR; qs = &rs->dlnext ) { /* zap part of list */
|
||
rs = *qs;
|
||
if( namematch(nm,rs->dlname) ) {
|
||
*qs = rs->dlnext;
|
||
free(rs);
|
||
return TRUE;
|
||
}
|
||
}
|
||
return FALSE; /* thru loop, can't find it */
|
||
}
|
||
|
||
namematch(s1,s2)
|
||
BYTE *s1, *s2;
|
||
{
|
||
for( ; *s1 && *s2; ++s1, ++s2 )
|
||
if( toupper(*s1) != toupper(*s2) )
|
||
return FALSE;
|
||
if( *s1 || *s2 )
|
||
return FALSE;
|
||
else return TRUE;
|
||
}
|
||
|
||
|
||
/**************************************************************************/
|
||
#define PAGEWIDTH 72
|
||
rsp_display(rp)
|
||
DLIST *rp;
|
||
{
|
||
WORD ii;
|
||
|
||
printf("\nRSPs to be included are:\n");
|
||
for( ii=0; rp!=NULLPTR; rp = rp->dlnext ) {
|
||
if( (ii += 15) > PAGEWIDTH ) {
|
||
printf("\n");
|
||
ii=15;
|
||
}
|
||
printf(" %12.12s",rp->dlname);
|
||
}
|
||
printf("\n");
|
||
}
|
||
|
||
|
||
/**************************************************************************/
|
||
/* grpseek: seeks in MOD file 'fd' to the start of a code/data group, */
|
||
/* returns length (in bytes) of that group */
|
||
/*************************************************************************/
|
||
LONG
|
||
grpseek(fde,gt)
|
||
WORD fde; /* file descriptor */
|
||
WORD gt; /* group type to look for */
|
||
{
|
||
WORD gc; /* group counter */
|
||
LONG dps; /* pgphs to group base in file */
|
||
GROUP grp; /* structure for Cmd Hdr info */
|
||
|
||
if( lseek(fde,0L,0) < 0 ) /* seek to beginning of file */
|
||
CRASH("grp cmd header seek failed\n");
|
||
dps=8; /* pgphs to start of load group */
|
||
for( gc=0; gc<8; gc++ ) { /* search up to 8 groups in cmd hdr */
|
||
read(fde,&grp,sizeof(grp)); /* read each group in header */
|
||
if( grp.gtype == gt ) /* the group we want */
|
||
break;
|
||
dps += grp.glen; /* add in size of previous group */
|
||
}
|
||
if( grp.gtype != gt ) /* did we find the group? */
|
||
return ((LONG) FAILURE); /* nope, so fail */
|
||
dps = dps << 4; /* pgphs xfm to bytes */
|
||
if( lseek(fde,dps,0) < 0 ) /* seek to start of data group */
|
||
CRASH("grp group seek failed\n");
|
||
return ((LONG)((grp.glen)<<4)); /* return group size in bytes */
|
||
}
|
||
|
||
|
||
/**************************************************************************/
|
||
/* xfer rtns: transfer a group from file 'module' to file NEWSYS (fns)
|
||
/* returns number of paragraphs in the group
|
||
/**************************************************************************/
|
||
UWORD
|
||
xfergrp(module,group_type)
|
||
BYTE *module; /* module name */
|
||
WORD group_type; /* code? or data? */
|
||
{
|
||
REG WORD fm; /* file descriptor for module */
|
||
REG UWORD rv,xferpart_grp(); /* return value */
|
||
|
||
if( (fm=BROPEN(module)) < 0 ) /* open the module for binary reading */
|
||
CRASH("can't find a system module\n");
|
||
rv = xferpart_grp(fm,group_type,0);
|
||
close(fm);
|
||
return rv;
|
||
}
|
||
|
||
/**************************************************************************/
|
||
UWORD
|
||
xferpart_grp(fm,gt,skip)
|
||
WORD fm; /* file descriptor for module */
|
||
WORD gt; /* group type: code or data */
|
||
UWORD skip; /* num pgphs to skip in this group */
|
||
{
|
||
REG WORD ii; /* counter */
|
||
REG LONG xx, yy; /* long counters */
|
||
BYTE xferbuf[BUFSIZ]; /* a transfer buffer */
|
||
GROUP grp; /* a group area */
|
||
|
||
if( lseek(fm,0L,0) < 0 ) /* seek to beginning of file */
|
||
CRASH("grp cmd header seek failed\n");
|
||
yy = skip+8; /* num pgphs to skip + in cmd hdr */
|
||
for( ii=0; ii<8; ++ii ) { /* read group hdrs in cmd hdr */
|
||
read(fm,&grp,sizeof(grp));
|
||
if( grp.gtype == gt )
|
||
break;
|
||
yy += grp.glen; /* count #pgphs in this group to skip */
|
||
}
|
||
if( grp.gtype!=gt ) CRASH("module doesn't have group\n");
|
||
xx = yy << 4; /* cvt to bytes */
|
||
if( lseek(fm,xx,0)<0 ) CRASH("couldn't seek in module\n");
|
||
xx = grp.glen; xx -= skip; /* pgphs to xfer */
|
||
for( yy=xx<<4; yy>0; yy-=ii ){ /* xfer bytes to NEWSYS */
|
||
ii = ( yy > BUFSIZ ? BUFSIZ : yy ); /* num bytes per xfer */
|
||
if( read(fm,xferbuf,ii) != ii ) CRASH("not enough bytes in module\n");
|
||
write(fns,xferbuf,ii);
|
||
}
|
||
return (UWORD)(xx); /* convert to pgphs */
|
||
}
|
||
|
||
|
||
|
||
/**************************************************************************/
|
||
/* help: prints out a help message */
|
||
/**************************************************************************/
|
||
|
||
BYTE *helpm1[] = {
|
||
"\n\n",
|
||
#ifdef MCPM
|
||
"\t\t*** GENCMPM Help Function ***",
|
||
"\t\t=============================",
|
||
" GENCMPM lets you edit and/or generate a system image from",
|
||
#else
|
||
"\t\t*** GENCCPM Help Function ***",
|
||
"\t\t============================",
|
||
" GENCCPM lets you edit and/or generate a system image from",
|
||
#endif
|
||
"operating system modules on the default drive. A detailed",
|
||
"explanation of each parameter may be found in the Concurrent CP/M-86",
|
||
"System Guide, Section 2.\n",
|
||
#ifdef MCPM
|
||
" GENCMPM assumes the default values shown within square",
|
||
#else
|
||
" GENCCPM assumes the default values shown within square",
|
||
#endif
|
||
"brackets. All numbers are Hexadecimal. To change a parameter,",
|
||
"enter the parameter name followed by '=' and the new value. Type",
|
||
"<CR> (a carriage return) to enter the assignment. You can make",
|
||
"multiple assignments if you separate them by a space. No spaces",
|
||
"are allowed within an assignment. Example:\n",
|
||
"CHANGES? verbose=N sysdrive=A: openmax=1A <CR>\n",
|
||
"Parameter names may be shortened to the minimum combination of",
|
||
"letters unique to the currently displayed menu. Example:\n",
|
||
"CHANGES? v=N sysd=A: op=1a <CR>\n",
|
||
NULLPTRI
|
||
};
|
||
BYTE *helpm2[] = {
|
||
"\n\n",
|
||
"Sub-menus (the last few options without default values) are accessed",
|
||
"by typing the sub-menu name followed by <CR>. You may enter",
|
||
"multiple sub-menus, in which case each sub-menu will be displayed",
|
||
"in order. Example:\n",
|
||
"CHANGES? help sysparams rsps <CR>\n",
|
||
"Enter <CR> alone to exit a menu, or a parameter name, '=' and the",
|
||
"new value to assign a parameter. Multiple assignments may be",
|
||
"entered, as in response to the Main Menu prompt.\n",
|
||
NULLPTRI
|
||
};
|
||
|
||
|
||
BYTE *
|
||
help(tx) /* print a helpful message to user */
|
||
BYTE *tx;
|
||
{
|
||
REG BYTE **cpp; /* pointer to help strings */
|
||
|
||
for( cpp=helpm1; *cpp != NULLPTR; cpp++ )
|
||
printf("%s\n",*cpp);
|
||
press_return();
|
||
for( cpp=helpm2; *cpp != NULLPTR; cpp++ )
|
||
printf("%s\n",*cpp);
|
||
press_return();
|
||
return NULLPTR;
|
||
}
|
||
|
||
/************************************************************************/
|
||
/* memory list allocation */
|
||
/**************************************************************************/
|
||
|
||
|
||
BYTE *
|
||
domem(cmdval,memtitle)
|
||
BYTE *cmdval;
|
||
BYTE *memtitle;
|
||
{
|
||
WORD cntmlist(); /* does list validation */
|
||
BOOLEAN okl; /* okay list */
|
||
BYTE cmds[CMDSLEN]; /* place to put input */
|
||
EXTERN MLIST *memroot; /* memory list root */
|
||
EXTERN MENU *memmenu; /* memory edit menu */
|
||
EXTERN BYTE *clearit;
|
||
|
||
okl = (cntmlist(memroot) > 0); /* overlap chk & condense */
|
||
if(cmdval!=NULLPTR) {
|
||
domenu(cmdval,memmenu); /* do the commands */
|
||
okl = (cntmlist(memroot)>0);/* check the results */
|
||
}
|
||
if( !okl || cmdval==NULLPTR ) /* do we need to interact with user? */
|
||
FOREVER { /* display, the edit */
|
||
printf("%s",clearit); /* clear the screen (maybe) */
|
||
dspmlist(memroot); /* here's what it looks like */
|
||
prtmenu(memtitle,memmenu); /* here's how to edit */
|
||
printf(PROMPT); /* what to do? */
|
||
if( gets(cmds)!=cmds || *cmds==NULL ) { /* see if the want to get out */
|
||
if(okl)
|
||
break;
|
||
else {
|
||
printf("Please adjust memory partitions\n");
|
||
press_return();
|
||
continue;
|
||
}
|
||
}
|
||
domenu(cmds,memmenu); /* edit the memory list */
|
||
okl = (cntmlist(memroot)>0);/* validate the memory list */
|
||
}
|
||
return NULLPTR; /* standard return */
|
||
}
|
||
|
||
|
||
/**************************************************************************/
|
||
BYTE *
|
||
addmem(ms) /* add memory partitions */
|
||
BYTE *ms; /* memory partition spec */
|
||
{
|
||
REG BYTE *pl; /* pointer to last addr spec */
|
||
REG BYTE *ps; /* pointer to size spec */
|
||
UWORD f, l, qq, s; /* values of spec */
|
||
MLIST *intomlist(), *mnew; /* where to put them */
|
||
EXTERN MLIST *memroot; /* memory partitions list */
|
||
BYTE *badspec = "Add memory partition spec should look like:\n\tadd=first,last,size";
|
||
BYTE *badval = "Spec: add=first,last,size\n\twhere last>first, size>80";
|
||
BYTE *warnbig = "Warning: size too big, it will be truncated";
|
||
BYTE *warnleft = "Warning: region not evenly divided by size, will adjust last partition";
|
||
BYTE *rval;
|
||
BYTE *index();
|
||
|
||
rval = NULLPTR; /* default return value */
|
||
if( (pl=index(ms,','))==0) /* look for ptr to last addr */
|
||
return badspec;
|
||
else *pl++ = NULL; /* terminate first addr spec */
|
||
if( (ps=index(pl,','))==0) /* look for ptr to size */
|
||
return badspec;
|
||
else *ps++ = NULL;
|
||
f=atoih(ms); /* convert first addr spec */
|
||
s=atoih(ps); /* convert size spec */
|
||
if( *pl=='+' ) /* last addr relative to first? */
|
||
l=atoih(pl+1)+f; /* yes, so calculate */
|
||
else if( *pl==NULL || *pl=='*' ) {
|
||
if( *pl=='*' ) /* last addr multiple of size? */
|
||
l=atoih(pl+1); /* spec multiple */
|
||
else l=1; /* default multiple=1 */
|
||
l = f+l*s; /* s in paragraphs */
|
||
} else l=atoih(pl); /* no, it's absolute address */
|
||
if( l<=f || s==0 ) /* 1st validation check */
|
||
return badval;
|
||
if( s > l-f ) { /* 2nd validation check */
|
||
rval = warnbig;
|
||
s = l-f;
|
||
}
|
||
if( s<MINKMEM ) /* 3rd validation check */
|
||
return "Memory partition must be at least 80 paragraphs";
|
||
qq = ((l-f)/s)*s; /* make sure last == first + xx * s */
|
||
if( qq != (l-f) ) { /* 4th validation check */
|
||
rval = warnleft;
|
||
l = f+qq;
|
||
}
|
||
mnew = (MLIST *)malloc(sizeof(*mnew)); /* make room */
|
||
mnew->mlfirst = f;
|
||
mnew->mllast = l;
|
||
mnew->mlsize = s;
|
||
memroot=intomlist(memroot,mnew); /* sorted insertion into list */
|
||
return rval; /* everything okay */
|
||
}
|
||
|
||
|
||
/**************************************************************************/
|
||
BYTE *
|
||
delmem(ms) /* delete memory partition */
|
||
BYTE *ms;
|
||
{
|
||
REG WORD df, dl; /* delete first, last */
|
||
MLIST **mm, **mn, *mo, *mp, *mq; /* necessary list ptrs */
|
||
EXTERN MLIST *memroot; /* memory partitions list */
|
||
BYTE *pl;
|
||
WORD i;
|
||
BYTE *badspec="To delete a memory partition, say\n\tdelete=1 or delete=1-3\n";
|
||
|
||
if( *ms == '*' ) { /* delete all? */
|
||
for( mp=memroot; mp!=NULLPTR; mp=mq ) {
|
||
mq = mp->mlnext; /* save the pointer before we free it */
|
||
free(mp);
|
||
}
|
||
memroot = NULLPTR;
|
||
return NULLPTR; /* everything okay */
|
||
}
|
||
if( (pl=index(ms,'-')) == 0 )
|
||
pl=ms; /* point last to first */
|
||
else *pl++ = NULL; /* else point to after 'dash' */
|
||
df=atoi(ms); /* decimal conversion */
|
||
dl=atoi(pl);
|
||
for( i=1, mm=&memroot, mn=NULLPTR, mo=memroot;
|
||
i<=dl && mo!=NULLPTR;
|
||
++i ) {
|
||
if( i==df ) mn=mm; /* found first, pt to ptr to */
|
||
mm = &mo->mlnext; /* ptr to ptr */
|
||
mo = mo->mlnext;
|
||
}
|
||
if( mn==NULLPTR || i<=dl ) /* check range of deletions */
|
||
return badspec;
|
||
mp = *mn; /* save ptr to deleted list */
|
||
*mn = mo; /* cut them suckers out of the list */
|
||
for( ; mp!=mo; mp=mq ) {
|
||
mq = mp->mlnext;
|
||
free(mp);
|
||
}
|
||
return NULLPTR; /* everything ok */
|
||
}
|
||
|
||
|
||
|
||
/**************************************************************************/
|
||
dspmlist(mroot)
|
||
MLIST *mroot;
|
||
{
|
||
MLIST *mn, *mo;
|
||
REG WORD i, nump;
|
||
|
||
printf("\n\n");
|
||
printf(" Addresses Partitions (in paragraphs)\n");
|
||
printf(" # Start Last Size Qty \n");
|
||
for( i=1, mn=mroot; mn!=NULLPTR; ++i, mn=mo ) {
|
||
nump = (mn->mllast-mn->mlfirst) / mn->mlsize;
|
||
printf("%2.2d. %4.4xh %4.4xh %4.4xh %4.4xh ",
|
||
i,mn->mlfirst,mn->mllast,mn->mlsize,nump);
|
||
if( (mo=mn->mlnext) != NULLPTR ) { /* do some checking */
|
||
if( mn->mllast > mo->mlfirst )
|
||
printf("**overlaps** ");
|
||
if( mn->mlsize > mn->mllast-mn->mlfirst )
|
||
printf("**partition too big** ");
|
||
}
|
||
printf("\n");
|
||
}
|
||
}
|
||
|
||
|
||
/**************************************************************************/
|
||
WORD
|
||
cntmlist(mroot) /* check for overlaps, condense if possible */
|
||
MLIST *mroot; /* returns number mem partitions, 0 if bad list */
|
||
{
|
||
MLIST *mn, *mo; /* ptr within list */
|
||
REG BOOLEAN olap; /* partitions overlap or bad size */
|
||
REG WORD nump; /* number of partitions this block */
|
||
REG WORD totnump; /* keep the count going */
|
||
|
||
totnump = 0; /* total number partitions */
|
||
olap = FALSE; /* innocent until proven guilty */
|
||
for( mn=mroot; mn!=NULLPTR && (mo=mn->mlnext)!=NULLPTR; ) {
|
||
if( mn->mlsize==mo->mlsize ){ /* partitions same size? */
|
||
if( mn->mlfirst==mo->mlfirst && /* same partitions? */
|
||
mn->mllast==mo->mllast ) {
|
||
mn->mlnext=mo->mlnext;
|
||
free(mo); /* mo is redundant, zap it */
|
||
continue;
|
||
} else
|
||
if( mn->mllast==mo->mlfirst || /* adjacent partition? */
|
||
mn->mllast==(mo->mlfirst-1) ) {
|
||
mn->mllast=mo->mllast; /* make 1st partition bigger */
|
||
mn->mlnext=mo->mlnext; /* zap out mo from list */
|
||
free(mo); /* we don't need it any more */
|
||
continue;
|
||
}
|
||
}
|
||
if( mn->mllast > mo->mlfirst )
|
||
olap=TRUE; /* partitions overlap */
|
||
nump = (mn->mllast-mn->mlfirst) / mn->mlsize;
|
||
if( nump<=0 )
|
||
olap=TRUE; /* size > partition */
|
||
else totnump += nump; /* incr this count */
|
||
mn=mo; /* continue through loop */
|
||
}
|
||
if( mn!=NULLPTR ) { /* catch the last in the loop */
|
||
nump = (mn->mllast-mn->mlfirst) / mn->mlsize;
|
||
if( nump<=0 )
|
||
olap=TRUE; /* size > partition */
|
||
else totnump += nump; /* incr this count */
|
||
}
|
||
if( olap )
|
||
return 0; /* boo boo, return 0 */
|
||
else return totnump; /* return num partitions */
|
||
}
|
||
|
||
|
||
|
||
/**************************************************************************/
|
||
MLIST *
|
||
intomlist(mroot,mi) /* insert mi into list mroot sorted */
|
||
MLIST *mroot;
|
||
MLIST *mi;
|
||
{
|
||
MLIST **mm; /* ptr to ptr to list */
|
||
MLIST *mn; /* ptr to list */
|
||
|
||
for( mm=&mroot, mn=mroot;
|
||
mn != NULLPTR && mi->mlfirst > mn->mlfirst; ){
|
||
mm = &mn->mlnext;
|
||
mn = mn->mlnext;
|
||
}
|
||
mi->mlnext = mn;
|
||
*mm = mi;
|
||
return mroot;
|
||
}
|
||
|
||
/**************************************************************************/
|
||
UWORD /* returns new size of partition, 0 if not enough room */
|
||
trimit(start,last,olds)
|
||
UWORD start; /* start address of partition */
|
||
UWORD last; /* end address of partition */
|
||
UWORD olds; /* old partition size */
|
||
{
|
||
REG UWORD ss;
|
||
|
||
ss = last-start; /* size is in paragraphs */
|
||
if( ss<MINKMEM ) return 0; /* sorry, too small */
|
||
else if( ss<olds ) return ss-1; /* needs to be smaller */
|
||
else return olds; /* fine just the way it is */
|
||
}
|
||
|
||
WORD
|
||
onbounds(start,size,nst)
|
||
UWORD start; /* original starting boundary */
|
||
UWORD size; /* partition size */
|
||
UWORD nst; /* new starting address */
|
||
{ /* returns addr>nst multiple of size from start */
|
||
REG UWORD rr;
|
||
|
||
for( rr=start; rr<nst; rr += size )
|
||
;
|
||
return rr;
|
||
}
|
||
|
||
/**************************************************************************/
|
||
/* trimlist: trims the memory list according to OS bounds */
|
||
/**************************************************************************/
|
||
|
||
BOOLEAN /* returns TRUE iff any adjustments */
|
||
trimlist(osstart,osend)
|
||
UWORD osstart; /* starting pgph */
|
||
UWORD osend; /* ending pgph */
|
||
{
|
||
EXTERN MLIST *memroot;
|
||
REG MLIST **mm, *mn, *mo; /* ptrs into memlist */
|
||
REG UWORD ss, zz; /* temp vars */
|
||
LOCAL WORD adjusts; /* number of collisions */
|
||
|
||
adjusts = 0; /* we haven't adjusted anything yet */
|
||
for( mm=&memroot, mn=memroot; mn!=NULLPTR; mn=*mm ) {
|
||
if( mn->mlfirst < osstart ) {
|
||
if( mn->mllast >= osstart ) { /** collision **/
|
||
++adjusts; /* we're doing some adjusting */
|
||
if( mn->mllast > osend ) { /* real big mem part? */
|
||
mo = (MLIST *)malloc(sizeof *mo); /* set it up now, adjust it later */
|
||
mo->mlfirst = onbounds(mn->mlfirst,mn->mlsize,osstart);
|
||
mo->mllast = mn->mllast;
|
||
mo->mlsize = mn->mlsize;
|
||
mo->mlnext = mn->mlnext;
|
||
mn->mlnext = mo;
|
||
}
|
||
if( (zz=trimit(mn->mlfirst,osstart-1,mn->mlsize)) > 0 ) {
|
||
mn->mllast = osstart-1;
|
||
mn->mlsize = zz; /* in case it was trimmed */
|
||
} else { /* partitions too small, delete it */
|
||
*mm = mn->mlnext;
|
||
free(mn);
|
||
continue; /* don't increment list ptr */
|
||
}
|
||
} /**** end collision ****/
|
||
|
||
} else if( mn->mlfirst < osend ) { /** collision **/
|
||
++adjusts; /* we're doing some adjusting */
|
||
if( mn->mllast <= osend ) { /* does part cross past os? */
|
||
*mm = mn->mlnext; /* no, delete it */
|
||
free(mn);
|
||
continue;
|
||
}
|
||
ss = onbounds(mn->mlfirst,mn->mlsize,osend);
|
||
if( (zz=trimit(osend,ss,mn->mlsize)) > 0 ){/* set up a smaller mem part */
|
||
mo = (MLIST *)malloc(sizeof *mo);
|
||
mo->mlfirst = osend+1;
|
||
mo->mllast = ss;
|
||
mo->mlsize = zz;
|
||
mo->mlnext = mn;
|
||
*mm = mo;
|
||
mm = &mo->mlnext;
|
||
}
|
||
if( (zz=trimit(ss,mn->mllast,mn->mlsize)) > 0 ){
|
||
mn->mlfirst = ss;
|
||
mn->mlsize = zz;
|
||
} else { /* partition too small, delete */
|
||
*mm = mn->mlnext;
|
||
free(mn);
|
||
continue; /* don't bottom out on this loop */
|
||
}
|
||
} /**** end collision ****/
|
||
|
||
mm = &mn->mlnext; /* set up for next partition check */
|
||
} /**** end FOR loop ***/
|
||
return adjusts>0; /* returns TRUE if we adjusted */
|
||
}
|
||
|
||
|
||
|
||
|
||
|