You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
482 lines
9.9 KiB
482 lines
9.9 KiB
/*---------------------------------------------------------------------------
|
|
FILE : PLEX.C
|
|
AUTHOR: STOLEN FROM EXCEL modified by NavPal
|
|
This file contains routines used to manipulate the PL (pronounced:
|
|
"plex") structures.
|
|
----------------------------------------------------------------------------*/
|
|
#include "priv.h"
|
|
#pragma hdrstop
|
|
|
|
/*-----------------------------------------------------------------------
|
|
| FInRange
|
|
| Simple little routine that tells you if a number lies within a
|
|
| range.
|
|
|
|
|
|
|
|
| Arguments:
|
|
| w: Number to check
|
|
| wFirst: First number in the range
|
|
| wLast: Last number in the range
|
|
|
|
|
| Returns:
|
|
| fTrue if the number is in range
|
|
|
|
|
| Keywords: in range check
|
|
-----------------------------------------------------------------------*/
|
|
BOOL FInRange(w, wFirst, wLast)
|
|
int w;
|
|
int wFirst, wLast;
|
|
{
|
|
Assert(wLast >= wFirst);
|
|
return(w >= wFirst && w <= wLast);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
/*----------------------------------------------------------------------------
|
|
| FValidPl
|
|
|
|
|
| Checks for a valid PL structure.
|
|
|
|
|
| Arguments:
|
|
| ppl PL to check
|
|
|
|
|
| Returns:
|
|
| fTrue if the PL looks reasonable.
|
|
----------------------------------------------------------------------------*/
|
|
BOOL FValidPl(pvPl)
|
|
VOID *pvPl;
|
|
{
|
|
PL * ppl;
|
|
|
|
ppl = (PL *) pvPl;
|
|
|
|
if (ppl== NULL ||
|
|
ppl->cbItem == 0 ||
|
|
ppl->iMac < 0 ||
|
|
ppl->iMax < 0 ||
|
|
ppl->iMax < ppl->iMac)
|
|
{
|
|
return(fFalse);
|
|
}
|
|
|
|
return(fTrue);
|
|
}
|
|
#endif //DEBUG
|
|
|
|
/*----------------------------------------------------------------------------
|
|
| CbPlAlloc
|
|
|
|
|
| Returns amount of memory allocated to the given PL
|
|
|
|
|
| Arguments:
|
|
| ppl PL to return info for.
|
|
|
|
|
| Returns:
|
|
| memory allocated to the PL
|
|
----------------------------------------------------------------------------*/
|
|
int CbPlAlloc(pvPl)
|
|
VOID *pvPl;
|
|
{
|
|
PL * ppl;
|
|
ppl = (PL *) pvPl;
|
|
|
|
if (ppl == NULL)
|
|
return(0);
|
|
|
|
Assert(FValidPl(ppl));
|
|
|
|
return(WAlign(cbPL + (ppl->iMax * ppl->cbItem)));
|
|
}
|
|
/*----------------------------------------------------------------------------
|
|
| FreePpl
|
|
|
|
|
| Frees a PL.
|
|
|
|
|
| Arguments:
|
|
| ppl PL to free
|
|
|
|
|
| Returns:
|
|
| Nothing.
|
|
----------------------------------------------------------------------------*/
|
|
void FreePpl(pvPl)
|
|
VOID *pvPl;
|
|
{
|
|
|
|
Assert(FValidPl(pvPl));
|
|
|
|
LocalFree(pvPl);
|
|
}
|
|
/*----------------------------------------------------------------------------
|
|
| PplAlloc
|
|
|
|
|
| Allocates and initializes a PL.
|
|
|
|
|
| Arguments:
|
|
| cbItem sizeof structure in the PL
|
|
| dAlloc number of items to allocate at a time
|
|
| iMax number of items in initial allocation
|
|
|
|
|
| Returns:
|
|
| Pointer to PL.
|
|
|
|
|
| Notes:
|
|
| returns NULL if OOM
|
|
----------------------------------------------------------------------------*/
|
|
VOID *PplAlloc(cbItem, dAlloc, iMax)
|
|
unsigned cbItem;
|
|
int dAlloc;
|
|
unsigned iMax;
|
|
{
|
|
PL *ppl;
|
|
long cb;
|
|
|
|
if (iMax > 32767) /* not too likely, but what the heck. */
|
|
return(NULL);
|
|
|
|
Assert((cbItem>=1 && cbItem<=65535u) && FInRange(dAlloc, 1, 31));
|
|
|
|
cb = WAlign((long) cbPL + (long) cbItem * (long) iMax);
|
|
|
|
ppl = (PL *) LocalAlloc( LPTR, cb );
|
|
if(ppl==NULL)
|
|
return(NULL);
|
|
|
|
ppl->cbItem = cbItem;
|
|
ppl->dAlloc = dAlloc;
|
|
ppl->iMax = iMax;
|
|
ppl->fUseCount = fFalse;
|
|
|
|
Assert(FValidPl(ppl));
|
|
|
|
return(ppl);
|
|
}
|
|
/*----------------------------------------------------------------------------
|
|
| IAddPl
|
|
|
|
|
| Adds an item to a PL.
|
|
|
|
|
| Arguments:
|
|
| pppl Pointer to PL. May change if reallocated.
|
|
| pv New item to add.
|
|
|
|
|
| Returns:
|
|
| Index of new item.
|
|
|
|
|
| Notes:
|
|
| returns -1 if OOM
|
|
----------------------------------------------------------------------------*/
|
|
int IAddPl(ppvPl, pv)
|
|
VOID **ppvPl;
|
|
VOID *pv;
|
|
{
|
|
int cbItem;
|
|
int iMac;
|
|
PL *ppl, *pplNew;
|
|
|
|
ppl = *ppvPl;
|
|
|
|
Assert(FValidPl(ppl));
|
|
|
|
cbItem = ppl->cbItem;
|
|
iMac = ppl->iMac;
|
|
|
|
if (iMac == ppl->iMax)
|
|
{
|
|
pplNew = PplAlloc(cbItem, ppl->dAlloc, iMac + ppl->dAlloc);
|
|
if(pplNew==NULL)
|
|
return(-1);
|
|
|
|
pplNew->fUseCount = ppl->fUseCount;
|
|
CopyMemory( pplNew->rg, ppl->rg, iMac * cbItem);
|
|
/* pplNew->iMac = iMac; /* This is not needed because hppl->iMac will be over-written later */
|
|
FreePpl(ppl);
|
|
*ppvPl = ppl = pplNew;
|
|
}
|
|
|
|
CopyMemory( &ppl->rg[iMac * cbItem], pv, cbItem );
|
|
ppl->iMac = iMac + 1;
|
|
|
|
Assert(FValidPl(*ppvPl));
|
|
|
|
return(iMac);
|
|
}
|
|
/*----------------------------------------------------------------------------
|
|
| RemovePl
|
|
|
|
|
| Removes an item from a PL.
|
|
|
|
|
| Arguments:
|
|
| ppl PL to remove item from
|
|
| i index of item to remove
|
|
|
|
|
| Returns:
|
|
| fTrue if an item was removed (only fFalse for use count plexes).
|
|
----------------------------------------------------------------------------*/
|
|
BOOL RemovePl(pvPl, i)
|
|
VOID *pvPl;
|
|
int i;
|
|
{
|
|
int iMac;
|
|
int cbItem;
|
|
BYTE *p;
|
|
PL * ppl;
|
|
|
|
ppl = (PL *) pvPl;
|
|
|
|
Assert(FValidPl(ppl) && i < ppl->iMac);
|
|
|
|
iMac = ppl->iMac;
|
|
cbItem = ppl->cbItem;
|
|
p = &ppl->rg[i * cbItem];
|
|
if (i != iMac - 1)
|
|
{
|
|
CopyMemory( p, p+cbItem, (iMac - i - 1) * cbItem );
|
|
}
|
|
ppl->iMac = iMac - 1;
|
|
|
|
Assert(FValidPl(ppl));
|
|
|
|
return fTrue;
|
|
}
|
|
/*----------------------------------------------------------------------------
|
|
| ILookupPl
|
|
|
|
|
| Searches a PL for an item.
|
|
|
|
|
| Arguments:
|
|
| ppl PL to lookup into
|
|
| p item to lookup
|
|
| pfnSgn Comparison function
|
|
|
|
|
| Returns:
|
|
| index of item, if found.
|
|
| -1 if not found.
|
|
----------------------------------------------------------------------------*/
|
|
int ILookupPl(pvPl, pvItem, pfnSgn)
|
|
VOID *pvPl;
|
|
VOID *pvItem;
|
|
int (*pfnSgn)();
|
|
{
|
|
int i;
|
|
BYTE *p;
|
|
PL * ppl;
|
|
|
|
ppl = (PL *) pvPl;
|
|
|
|
if (ppl == NULL)
|
|
return(-1);
|
|
|
|
Assert(FValidPl(ppl));
|
|
|
|
for (i = 0, p = ppl->rg; i < ppl->iMac; i++, p += ppl->cbItem)
|
|
{
|
|
if ((*(int (*)(void *, void *))pfnSgn)(p, pvItem) == sgnEQ)
|
|
{
|
|
return(i);
|
|
}
|
|
}
|
|
|
|
return(-1);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
| PLookupPl
|
|
|
|
|
| Searches a PL for an item
|
|
|
|
|
| Arguments:
|
|
| ppl PL to search
|
|
| pItem item to search for
|
|
| pfnSgn comparison function
|
|
|
|
|
| Returns:
|
|
| Pointer to item, if found
|
|
| Null, if not found
|
|
----------------------------------------------------------------------------*/
|
|
VOID *PLookupPl(pvPl, pvItem, pfnSgn)
|
|
VOID *pvPl;
|
|
VOID *pvItem;
|
|
int (*pfnSgn)();
|
|
{
|
|
int i;
|
|
|
|
if ((i = ILookupPl(pvPl, pvItem, pfnSgn)) == -1)
|
|
return(NULL);
|
|
|
|
return(&((PL *)pvPl)->rg[i * ((PL *)pvPl)->cbItem]);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
| FLookupSortedPl
|
|
|
|
|
| Searches a sorted PL for an item.
|
|
|
|
|
| Arguments:
|
|
| hppl PL to lookup into
|
|
| hpItem Item to lookup
|
|
| pi Index of found item (or insertion location if not)
|
|
| pfnSgn Comparison function
|
|
|
|
|
| Returns:
|
|
| index of item, if found.
|
|
| index of location to insert if not found.
|
|
----------------------------------------------------------------------------*/
|
|
int FLookupSortedPl(hpvPl, hpvItem, pi, pfnSgn)
|
|
VOID *hpvPl;
|
|
VOID *hpvItem;
|
|
int *pi;
|
|
int (*pfnSgn)();
|
|
{
|
|
int sgn;
|
|
unsigned iMin, iMid, iMac;
|
|
int cbItem;
|
|
BYTE *hprg;
|
|
BYTE *hpMid;
|
|
PL * hppl;
|
|
|
|
hppl = (PL *) hpvPl;
|
|
|
|
if ((hppl)==NULL)
|
|
{
|
|
*pi = 0;
|
|
return(fFalse);
|
|
}
|
|
|
|
Assert(FValidPl(hppl));
|
|
Assert(!hppl->fUseCount);
|
|
|
|
sgn = 1;
|
|
cbItem = hppl->cbItem;
|
|
iMin = iMid = 0;
|
|
iMac = hppl->iMac;
|
|
hprg = hppl->rg;
|
|
while (iMin != iMac)
|
|
{
|
|
iMid = iMin + (iMac-iMin)/2;
|
|
Assert(iMid != iMac);
|
|
|
|
hpMid = hprg + iMid*cbItem;
|
|
if ((sgn = (*(int (*)(void *, void *))pfnSgn)(hpMid, hpvItem)) == 0)
|
|
break;
|
|
|
|
/* Too low, look in upper interval */
|
|
if (sgn < 0)
|
|
iMin = ++iMid;
|
|
/* Too high, look in lower interval */
|
|
else
|
|
iMac = iMid;
|
|
}
|
|
|
|
/* Not found, return index of location to insert it */
|
|
*pi = iMid;
|
|
return(sgn == 0);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
| IAddNewPl
|
|
|
|
|
| Adds an item to a PL, creating the PL if it's initially NULL.
|
|
|
|
|
| Arguments:
|
|
| phppl pointer to PL
|
|
| hp pointer to item to add
|
|
| cbItem size of item
|
|
|
|
|
| Returns:
|
|
| the index of item added, if successful
|
|
| -1, if out-of-memory
|
|
----------------------------------------------------------------------------*/
|
|
int IAddNewPl(phpvPl, hpv, cbItem)
|
|
VOID **phpvPl;
|
|
VOID *hpv;
|
|
int cbItem;
|
|
{
|
|
int i;
|
|
PL ** phppl;
|
|
|
|
phppl = (PL **) phpvPl;
|
|
|
|
Assert(((*phppl)==NULL) || !(*phppl)->fUseCount);
|
|
|
|
i = -1;
|
|
|
|
if ((*phppl)==NULL)
|
|
{
|
|
*phppl = PplAlloc(cbItem, 5, 5);
|
|
}
|
|
|
|
if((*phppl)!=NULL)
|
|
{
|
|
Assert((*phppl)->cbItem == cbItem);
|
|
i = IAddPl((VOID **)phppl, hpv);
|
|
}
|
|
|
|
return(i);
|
|
}
|
|
|
|
/*----------------------------------------------------------------------------
|
|
| IAddNewPlPos
|
|
|
|
|
| Inserts an item into a plex at a specific position.
|
|
|
|
|
| Arguments:
|
|
| the index of the item added, if successful
|
|
| -1 if out-of-memory
|
|
----------------------------------------------------------------------------*/
|
|
int IAddNewPlPos(phpvPl, hpv, cbItem, i)
|
|
VOID **phpvPl;
|
|
VOID *hpv;
|
|
int cbItem;
|
|
int i;
|
|
{
|
|
BYTE *hpT;
|
|
PL ** phppl;
|
|
|
|
phppl = (PL **) phpvPl;
|
|
|
|
Assert(((*phppl)==NULL) || !(*phppl)->fUseCount);
|
|
|
|
if (IAddNewPl((VOID **)phppl, hpv, cbItem) == -1)
|
|
return(-1);
|
|
|
|
Assert(i < (*phppl)->iMac);
|
|
|
|
hpT = &(*phppl)->rg[i * cbItem];
|
|
// bltbh(hpT, hpT + cbItem, ((*phppl)->iMac - i - 1) * cbItem);
|
|
// bltbh(hpv, hpT, cbItem);
|
|
CopyMemory( hpT + cbItem, hpT, ((*phppl)->iMac - i - 1) * cbItem );
|
|
CopyMemory( hpT, hpv, cbItem );
|
|
|
|
Assert(FValidPl(*phppl));
|
|
|
|
return(i);
|
|
}
|
|
|
|
int IAddPlSort(phpvPl, hpv, pfnSgn)
|
|
VOID **phpvPl;
|
|
VOID *hpv;
|
|
int (*pfnSgn)();
|
|
{
|
|
int i;
|
|
|
|
#ifdef DEBUG
|
|
int iOld;
|
|
#endif
|
|
|
|
Assert((*phpvPl)!=NULL);
|
|
|
|
if (FLookupSortedPl(*phpvPl, hpv, &i, pfnSgn))
|
|
return(-1);
|
|
|
|
#ifdef DEBUG
|
|
iOld = i;
|
|
#endif
|
|
|
|
i = IAddNewPlPos(phpvPl, hpv, (*(PL **)phpvPl)->cbItem, i);
|
|
|
|
#ifdef DEBUG
|
|
Assert(i == -1 || i == iOld);
|
|
#endif
|
|
|
|
return(i);
|
|
}
|