mirror of https://github.com/lianthony/NT4.0
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.
1322 lines
26 KiB
1322 lines
26 KiB
//
|
|
// bsc1.cpp
|
|
//
|
|
// implementation of Bsc interface for single source of browser information
|
|
//
|
|
|
|
#include "pdbimpl.h"
|
|
|
|
#include "bsc1.h"
|
|
#include "helper.h"
|
|
|
|
#define _CRTBLD // Use copy from C runtime DLL
|
|
#include <..\undname\undname.h>
|
|
|
|
// create a BSC object using an existing PDB
|
|
PDBAPI(BOOL) Bsc::open(PDB* ppdb, OUT Bsc** ppbsc)
|
|
{
|
|
precondition(ppbsc);
|
|
precondition(ppdb);
|
|
|
|
Bsc1* pbsc1 = new Bsc1;
|
|
|
|
*ppbsc = pbsc1;
|
|
if (!pbsc1) return FALSE;
|
|
|
|
return pbsc1->init(ppdb);
|
|
}
|
|
|
|
PDBAPI(BOOL) Bsc::open(SZ szName, OUT Bsc** ppbsc)
|
|
{
|
|
precondition(ppbsc);
|
|
precondition(szName);
|
|
|
|
Bsc1* pbsc1 = new Bsc1;
|
|
|
|
*ppbsc = pbsc1;
|
|
if (!pbsc1) return FALSE;
|
|
|
|
pbsc1->fIOwnThePdb = TRUE;
|
|
|
|
EC ec;
|
|
char szError[cbErrMax];
|
|
PDB *pdb;
|
|
if (!PDB::Open(szName, "r", (SIG)0, &ec, szError, &pdb) ||
|
|
!pbsc1->init(pdb)) {
|
|
delete pbsc1;
|
|
*ppbsc = NULL;
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
Bsc1::Bsc1()
|
|
{
|
|
pdb = NULL;
|
|
pnm = NULL;
|
|
fIOwnThePdb = FALSE;
|
|
pstmModules = NULL;
|
|
pstmEntities = NULL;
|
|
cEntities = 0;
|
|
cModules = 0;
|
|
fCase = TRUE;
|
|
rgstm = NULL;
|
|
rghead = NULL;
|
|
rgimodSorted = NULL;
|
|
}
|
|
|
|
BOOL Bsc1::init(PDB *pdb_)
|
|
{
|
|
pdb = pdb_;
|
|
|
|
if (!NameMap::open(pdb_, FALSE, &pnm))
|
|
return FALSE;
|
|
|
|
if (!pdb->OpenStream(SZ_BSC_ENTITIES, &pstmEntities))
|
|
return FALSE;
|
|
|
|
cEntities = pstmEntities->QueryCb()/sizeof(ENTITY);
|
|
|
|
if (!cEntities)
|
|
return FALSE;
|
|
|
|
if (!pdb->OpenStream(SZ_BSC_MODULES, &pstmModules))
|
|
return FALSE;
|
|
|
|
cModules = pstmModules->QueryCb()/sizeof(NI);
|
|
|
|
if (!cModules)
|
|
return FALSE;
|
|
|
|
if (!rgEn.addSection(pstmEntities, 0, cEntities))
|
|
return FALSE;
|
|
|
|
rgModNi = new NI[cModules];
|
|
if (!rgModNi)
|
|
return FALSE;
|
|
|
|
if (!pstmModules->Read2(0, rgModNi,cModules*sizeof(NI)))
|
|
return FALSE;
|
|
|
|
if (!readModuleHeaders())
|
|
return FALSE;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
SZ Bsc1::szFrNi(NI ni)
|
|
{
|
|
return ::szFrNi (pnm, ni);
|
|
}
|
|
|
|
// helper functions for sorting things...
|
|
|
|
Bsc1 *pbscSorting;
|
|
|
|
int CmpImod(const void *p1, const void *p2)
|
|
{
|
|
IMOD i1 = *(IMOD*)p1;
|
|
IMOD i2 = *(IMOD*)p2;
|
|
|
|
BYTE h1 = pbscSorting->rgModIsHdr[i1];
|
|
BYTE h2 = pbscSorting->rgModIsHdr[i2];
|
|
|
|
if (h1 && !h2) return -1;
|
|
if (h2 && !h1) return 1;
|
|
|
|
NI ni1 = pbscSorting->rgModNi[i1];
|
|
NI ni2 = pbscSorting->rgModNi[i2];
|
|
|
|
if (ni1 < ni2)
|
|
return -1;
|
|
if (ni1 == ni2)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
int CmpIinst(const void *p1, const void *p2)
|
|
{
|
|
IINST i1 = *(IINST*)p1;
|
|
IINST i2 = *(IINST*)p2;
|
|
|
|
if (i1 < i2)
|
|
return -1;
|
|
if (i1 == i2)
|
|
return 0;
|
|
return 1;
|
|
}
|
|
|
|
BOOL Bsc1::readModuleHeaders()
|
|
{
|
|
char buf[512];
|
|
rgstm = (Stream**)malloc(cModules * sizeof(Stream*));
|
|
rghead = new BSC_HEAD[cModules];
|
|
rgidx = new MODIDX[cModules];
|
|
rgimodSorted = new IMOD[cModules];
|
|
rgModIsHdr = new BYTE[cModules];
|
|
|
|
if (!rgstm || !rghead || !rgidx || !rgimodSorted || !rgModIsHdr)
|
|
return FALSE;
|
|
|
|
for (IMOD imod = 0; imod < cModules; imod++) {
|
|
SZ szMod = szFrNi(rgModNi[imod]);
|
|
|
|
strcpy(buf, SZ_BSC_SRC_PREFIX);
|
|
strcat(buf, szMod);
|
|
|
|
if (!pdb->OpenStream(buf, &rgstm[imod]))
|
|
return FALSE;
|
|
|
|
Stream *pstm = rgstm[imod];
|
|
BSC_HEAD &bh = rghead[imod];
|
|
MODIDX *pmi = &rgidx[imod];
|
|
|
|
if (!pstm->QueryCb()) {
|
|
// empty stream -- special case avoid read
|
|
memset(&bh, 0, sizeof(bh));
|
|
}
|
|
|
|
else {
|
|
CB cb = sizeof(BSC_HEAD);
|
|
if (!pstm->Read(0, &bh, &cb) || cb != sizeof(BSC_HEAD))
|
|
return FALSE; // REVIEW : cleanup
|
|
|
|
if (bh.vers_major != BSC_VERS_MAJOR || bh.vers_minor != BSC_VERS_MINOR)
|
|
return FALSE; // REVIEW : cleanup
|
|
}
|
|
|
|
if (imod == 0) {
|
|
pmi->idefMin = 0;
|
|
pmi->irefMin = 0;
|
|
pmi->iuseMin = 0;
|
|
pmi->ibaseMin = 0;
|
|
pmi->ipropMin = 0;
|
|
}
|
|
else {
|
|
MODIDX *pp = &rgidx[imod-1];
|
|
BSC_HEAD *bp = &rghead[imod-1];
|
|
|
|
pmi->idefMin = pp->idefMin + bp->cdef;
|
|
pmi->irefMin = pp->irefMin + bp->cref;
|
|
pmi->iuseMin = pp->iuseMin + bp->cuse;
|
|
pmi->ibaseMin = pp->ibaseMin + bp->cbase;
|
|
pmi->ipropMin = pp->ipropMin + bp->cprop;
|
|
}
|
|
|
|
OFF off = sizeof(BSC_HEAD);
|
|
if (!rgProp.addSection(pstm, off, bh.cprop))
|
|
return FALSE;
|
|
|
|
off += bh.cprop*sizeof(BSC_PROP);
|
|
|
|
if (!rgDef.addSection(pstm, off, bh.cdef))
|
|
return FALSE;
|
|
off += bh.cdef*sizeof(BSC_DEF);
|
|
|
|
if (!rgRef.addSection(pstm, off, bh.cref))
|
|
return FALSE;
|
|
off += bh.cref*sizeof(BSC_REF);
|
|
|
|
if (!rgUse.addSection(pstm, off, bh.cuse))
|
|
return FALSE;
|
|
off += bh.cuse*sizeof(BSC_USE);
|
|
|
|
if (!rgUby.addSection(pstm, off, bh.cuse))
|
|
return FALSE;
|
|
off += bh.cuse*sizeof(BSC_UBY);
|
|
|
|
if (!rgBase.addSection(pstm, off, bh.cbase))
|
|
return FALSE;
|
|
off += bh.cbase*sizeof(BSC_BASE);
|
|
|
|
if (!rgDerv.addSection(pstm, off, bh.cbase))
|
|
return FALSE;
|
|
}
|
|
|
|
for (imod = 0; imod < cModules; imod++) {
|
|
rgimodSorted[imod] = imod;
|
|
|
|
char *p = _tcsrchr(szFrNi(rgModNi[imod]), '.');
|
|
|
|
BOOL fHdr = TRUE;
|
|
|
|
// this is just a hueristic to help us indentify those files
|
|
// which are more likely to be headers, this in turn helps
|
|
// us to display references in a better order than we otherwise
|
|
// would. In particular we want the prototype of a function to
|
|
// to be the first reference as often as possible and this helps
|
|
// us to do that...
|
|
|
|
if (p && _tcslen(p) <= 4) {
|
|
switch (p[1]) {
|
|
case 'c': case 'C': case 'B': case 'b': case 'f': case 'F':
|
|
fHdr = FALSE;
|
|
}
|
|
}
|
|
|
|
rgModIsHdr[imod] = fHdr;
|
|
}
|
|
|
|
pbscSorting = this;
|
|
qsort(rgimodSorted, cModules, sizeof(IMOD), CmpImod);
|
|
|
|
delete [] rgModIsHdr;
|
|
rgModIsHdr = NULL;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
// close and dispose of pdb if necessary...
|
|
BOOL Bsc1::close()
|
|
{
|
|
if (fIOwnThePdb) {
|
|
fIOwnThePdb = FALSE;
|
|
pdb->Close();
|
|
pdb = NULL;
|
|
}
|
|
|
|
if (pstmModules) {
|
|
pstmModules->Release();
|
|
pstmModules = NULL;
|
|
}
|
|
|
|
if (pstmEntities) {
|
|
pstmEntities->Release();
|
|
pstmEntities = NULL;
|
|
}
|
|
|
|
if (rgstm) {
|
|
for (IMOD i = 0; i < cModules; i++) {
|
|
if (rgstm[i])
|
|
rgstm[i]->Release();
|
|
rgstm[i] = NULL;
|
|
}
|
|
free(rgstm);
|
|
}
|
|
|
|
if (rgModNi) {
|
|
delete [] rgModNi;
|
|
rgModNi = NULL;
|
|
}
|
|
|
|
if (rgidx) {
|
|
delete [] rgidx;
|
|
rgidx = NULL;
|
|
}
|
|
|
|
if (rgimodSorted) {
|
|
delete [] rgimodSorted;
|
|
rgimodSorted = NULL;
|
|
}
|
|
|
|
if (rghead) {
|
|
delete [] rghead;
|
|
rghead = NULL;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
// primitives for getting the information that underlies a handle
|
|
BOOL Bsc1::iinstInfo(IINST iinst, OUT SZ *psz, OUT TYP *ptyp, OUT ATR *patr)
|
|
{
|
|
ENTITY en = rgEn[iinst];
|
|
*psz = szFrNi(en.ni);
|
|
*ptyp = en.typ;
|
|
*patr = en.atr;
|
|
return TRUE;
|
|
}
|
|
|
|
SZ Bsc1::szFrIinst(IINST iinst)
|
|
{
|
|
return szFrNi(rgEn[iinst].ni);
|
|
}
|
|
|
|
BOOL Bsc1::idefInfo(IDEF idef, OUT SZ *pszModule, OUT LINE *piline)
|
|
{
|
|
BSC_DEF br = rgDef[idef];
|
|
IMOD imod = (IMOD)rgDef.isectOfIel(idef);
|
|
*pszModule = szFrNi(rgModNi[imod]);
|
|
*piline = br.line;
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL Bsc1::irefInfo(IREF iref, OUT SZ *pszModule, OUT LINE *piline)
|
|
{
|
|
BSC_REF br = rgRef[iref];
|
|
IMOD imod = (IMOD)rgRef.isectOfIel(iref);
|
|
*pszModule = szFrNi(rgModNi[imod]);
|
|
*piline = br.line;
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL Bsc1::imodInfo(IMOD imod, OUT SZ *pszModule)
|
|
{
|
|
*pszModule = szFrNi(rgModNi[imod]);
|
|
return TRUE;
|
|
}
|
|
|
|
char *ptyptab[] = {
|
|
"undef", // SBR_TYP_UNKNOWN
|
|
"function", // SBR_TYP_FUNCTION
|
|
"label", // SBR_TYP_LABEL
|
|
"parameter", // SBR_TYP_PARAMETER
|
|
"variable", // SBR_TYP_VARIABLE
|
|
"constant", // SBR_TYP_CONSTANT
|
|
"macro", // SBR_TYP_MACRO
|
|
"typedef", // SBR_TYP_TYPEDEF
|
|
"struct_name", // SBR_TYP_STRUCNAM
|
|
"enum_name", // SBR_TYP_ENUMNAM
|
|
"enum_mem", // SBR_TYP_ENUMMEM
|
|
"union_name", // SBR_TYP_UNIONNAM
|
|
"segment", // SBR_TYP_SEGMENT
|
|
"group", // SBR_TYP_GROUP
|
|
"program", // SBR_TYP_PROGRAM
|
|
"class", // SBR_TYP_CLASSNAM
|
|
"mem_func", // SBR_TYP_MEMFUNC
|
|
"mem_var", // SBR_TYP_MEMVAR
|
|
};
|
|
|
|
#define C_ATR 12
|
|
|
|
char *patrtab[] = {
|
|
"local", // SBR_ATR_LOCAL
|
|
"static", // SBR_ATR_STATIC
|
|
"shared", // SBR_ATR_SHARED
|
|
"near", // SBR_ATR_NEAR
|
|
"common", // SBR_ATR_COMMON
|
|
"decl_only", // SBR_ATR_DECL_ONLY
|
|
"public", // SBR_ATR_PUBLIC
|
|
"named", // SBR_ATR_NAMED
|
|
"module", // SBR_ATR_MODULE
|
|
"virtual", // SBR_ATR_VIRTUAL
|
|
"private", // SBR_ATR_PRIVATE
|
|
"protected", // SBR_ATR_PROTECT
|
|
};
|
|
|
|
|
|
SZ Bsc1::szFrTyp(TYP typ)
|
|
{
|
|
return ptyptab[typ];
|
|
}
|
|
|
|
SZ Bsc1::szFrAtr(ATR atr)
|
|
{
|
|
static char buf[512];
|
|
buf[0] = 0;
|
|
for (int i=0; i < C_ATR; i++) {
|
|
if (atr & (1<<i)) {
|
|
if (buf[0])
|
|
strcat(buf, ":");
|
|
strcat(buf, patrtab[i]);
|
|
}
|
|
}
|
|
return buf;
|
|
}
|
|
|
|
// primitives for managing object instances (iinst)
|
|
BOOL Bsc1::getIinstByvalue(SZ szReqd, TYP typ, ATR atr, OUT IINST *piinst)
|
|
{
|
|
IINST iinst = iinstSupSz(szReqd);
|
|
|
|
if (iinst == iinstNil)
|
|
return iinstNil;
|
|
|
|
while (iinst < cEntities) {
|
|
ENTITY enT = rgEn[iinst];
|
|
if (cmpStr(szReqd, szFrNi(enT.ni)))
|
|
break;
|
|
|
|
if (typ == enT.typ && atr == enT.atr) {
|
|
*piinst = iinst;
|
|
return TRUE;
|
|
}
|
|
|
|
iinst++;
|
|
}
|
|
|
|
*piinst = iinstNil;
|
|
return FALSE;
|
|
}
|
|
|
|
Array<IINST> *parIinst;
|
|
Bsc1 *pbscCur;
|
|
|
|
static BOOL GatherOverloads(IINST iinst)
|
|
// gather up the possible overloads but first check to make sure
|
|
// the name is still in use...
|
|
{
|
|
if (pbscCur->fHasDefsOrRefs(iinst))
|
|
return parIinst->append(iinst);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL Bsc1::getOverloadArray(SZ sz, MBF mbf, OUT IINST **ppiinst, OUT ULONG *pciinst)
|
|
{
|
|
precondition(ppiinst);
|
|
precondition(pciinst);
|
|
IINST *rgiinst;
|
|
ULONG cIinst;
|
|
|
|
if (sz && sz[0] && sz[0] != '*') {
|
|
Array<IINST> arIinst;
|
|
parIinst = &arIinst;
|
|
pbscCur = this;
|
|
GenerateOverloads(sz, mbf, GatherOverloads,this);
|
|
cIinst = arIinst.size();
|
|
rgiinst = (IINST*)malloc(cIinst*sizeof(IINST));
|
|
if (!rgiinst) return FALSE;
|
|
|
|
for (UINT i=0; i < cIinst; i++)
|
|
rgiinst[i] = arIinst[i];
|
|
}
|
|
else {
|
|
rgiinst = (IINST*)malloc(cEntities*sizeof(IINST));
|
|
if (!rgiinst) return FALSE;
|
|
|
|
cIinst = 0;
|
|
|
|
for (UINT i = 0; i < cEntities; i++) {
|
|
if (fInstFilter(i, mbf) && fHasDefsOrRefs(i))
|
|
rgiinst[cIinst++] = i;
|
|
}
|
|
}
|
|
|
|
*ppiinst = rgiinst;
|
|
*pciinst = cIinst;
|
|
return TRUE;
|
|
}
|
|
|
|
IPROP Bsc1::ipropFrEn(ENTITY en, IMOD imod)
|
|
{
|
|
IPROP Lo = rgidx[imod].ipropMin;
|
|
IPROP Hi = Lo + rghead[imod].cprop;
|
|
IPROP ipropMac = Hi;
|
|
|
|
SZ szReqd = szFrNi(en.ni);
|
|
|
|
while (Lo < Hi) {
|
|
ULONG Mid = Lo + (Hi - Lo) / 2; // this way there can be no overflow
|
|
|
|
SZ szCur = szFrNi(rgProp[Mid].en.ni);
|
|
|
|
int Cmp = cmpStr(szCur, szReqd);
|
|
|
|
if (Cmp >= 0)
|
|
Hi = Mid;
|
|
else
|
|
Lo = Mid + 1;
|
|
}
|
|
|
|
if (Hi == ipropMac)
|
|
return ipropNil;
|
|
|
|
IPROP iprop = Hi;
|
|
|
|
while (iprop < ipropMac) {
|
|
ENTITY enT = rgProp[iprop].en;
|
|
|
|
// if we found something that doesn't match case-insenstively, we give up
|
|
if (_stricmp(szReqd, szFrNi(enT.ni)))
|
|
break;
|
|
|
|
// wait for the case sensitive match, we need an exact match because
|
|
// we're starting from an entity... the name has already been resolved
|
|
// to a specific object as far as the user is concerned
|
|
|
|
if (strcmp(szReqd, szFrNi(enT.ni))) {
|
|
iprop++;
|
|
continue;
|
|
}
|
|
|
|
if (en.typ == enT.typ && en.atr == enT.atr)
|
|
return iprop;
|
|
|
|
iprop++;
|
|
}
|
|
|
|
return ipropNil;
|
|
}
|
|
|
|
|
|
struct EnumProps
|
|
{
|
|
IMOD imod;
|
|
IMOD imodT;
|
|
BYTE mask;
|
|
int ib;
|
|
IPROP iprop;
|
|
ENTITY en;
|
|
Bsc1* pbsc;
|
|
ULONG iMac;
|
|
ULONG iCur;
|
|
ULONG MODIDX::*mBase;
|
|
BRIND BSC_PROP::*mIdx;
|
|
IPROP ipropBase;
|
|
ULONG cprobes;
|
|
|
|
EnumProps(Bsc1 *pbsc_, IINST iinst, ULONG MODIDX::*mBase_, BRIND BSC_PROP::*mIdx_)
|
|
{
|
|
pbsc = pbsc_;
|
|
mIdx = mIdx_;
|
|
mBase = mBase_;
|
|
|
|
en = pbsc->rgEn[iinst];
|
|
imodT = (IMOD)-1;
|
|
iMac = 0; iCur = 0; cprobes = 0;
|
|
}
|
|
|
|
BOOL next()
|
|
{
|
|
if (++iCur < iMac) {
|
|
return TRUE;
|
|
}
|
|
|
|
for ( ; ++imodT < pbsc->cModules ; ) {
|
|
imod = pbsc->rgimodSorted[imodT];
|
|
|
|
NI niMax = pbsc->rghead[imod].niMax;
|
|
if (en.ni > niMax) continue;
|
|
|
|
MaskFrNi(en.ni, niMax, CB_BITS_NI, &ib, &mask);
|
|
|
|
if (!(pbsc->rghead[imod].bitsNi[ib]&mask)) continue;
|
|
|
|
if ((iprop = pbsc->ipropFrEn(en, imod)) == ipropNil) continue;
|
|
|
|
ipropBase = pbsc->rgidx[imod].ipropMin;
|
|
|
|
pbsc->getIdxRange(imod, iprop, mBase, mIdx, iCur, iMac);
|
|
|
|
if (iCur >= iMac) continue;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
};
|
|
|
|
|
|
BOOL Bsc1::getUsedByArray(IINST iinst, MBF mbf, OUT IINST **ppiinst, OUT ULONG *pciinst)
|
|
{
|
|
Array<IINST> rgIinst;
|
|
|
|
EnumProps enm(this, iinst, &MODIDX::iuseMin, &BSC_PROP::iuby);
|
|
|
|
while (enm.next()) {
|
|
IPROP iprop = rgUby[enm.iCur].iprop + enm.ipropBase;
|
|
IINST ii = iinstFrEn(rgProp[iprop].en);
|
|
|
|
if (!fInstFilter(ii, mbf))
|
|
continue;
|
|
|
|
if (!ppiinst) { *pciinst = 1; return TRUE; }
|
|
rgIinst.append(ii);
|
|
}
|
|
|
|
return DupArray(ppiinst, pciinst, rgIinst);
|
|
}
|
|
|
|
BOOL Bsc1::getUsesArray(IINST iinst, MBF mbf, OUT IINST **ppiinst, OUT ULONG *pciinst)
|
|
{
|
|
Array<IINST> rgIinst;
|
|
|
|
EnumProps enm(this, iinst, &MODIDX::iuseMin, &BSC_PROP::iuse);
|
|
|
|
while (enm.next()) {
|
|
IPROP iprop = rgUse[enm.iCur].iprop + enm.ipropBase;
|
|
IINST ii = iinstFrEn(rgProp[iprop].en);
|
|
|
|
if (!fInstFilter(ii, mbf))
|
|
continue;
|
|
|
|
if (!ppiinst) { *pciinst = 1; return TRUE; }
|
|
rgIinst.append(ii);
|
|
}
|
|
|
|
return DupArray(ppiinst, pciinst, rgIinst);
|
|
}
|
|
|
|
BOOL Bsc1::getBaseArray(IINST iinst, OUT IINST **ppiinst, OUT ULONG *pciinst)
|
|
{
|
|
Array<IINST> rgIinst;
|
|
|
|
EnumProps enm(this, iinst, &MODIDX::ibaseMin, &BSC_PROP::ibase);
|
|
|
|
while (enm.next()) {
|
|
IPROP iprop = rgBase[enm.iCur].iprop + enm.ipropBase;
|
|
IINST ii = iinstFrEn(rgProp[iprop].en);
|
|
|
|
if (!ppiinst) { *pciinst = 1; return TRUE; }
|
|
rgIinst.append(ii);
|
|
}
|
|
|
|
return DupArray(ppiinst, pciinst, rgIinst);
|
|
}
|
|
|
|
BOOL Bsc1::getDervArray(IINST iinst, OUT IINST **ppiinst, OUT ULONG *pciinst)
|
|
{
|
|
Array<IINST> rgIinst;
|
|
|
|
EnumProps enm(this, iinst, &MODIDX::ibaseMin, &BSC_PROP::iderv);
|
|
|
|
while (enm.next()) {
|
|
IPROP iprop = rgDerv[enm.iCur].iprop + enm.ipropBase;
|
|
IINST ii = iinstFrEn(rgProp[iprop].en);
|
|
|
|
if (!ppiinst) { *pciinst = 1; return TRUE; }
|
|
rgIinst.append(ii);
|
|
}
|
|
|
|
return DupArray(ppiinst, pciinst, rgIinst);
|
|
}
|
|
|
|
BOOL Bsc1::getMembersArray(IINST iinst, MBF mbf, OUT IINST **ppiinst, OUT ULONG *pciinst)
|
|
{
|
|
Array<IINST> rgIinst;
|
|
|
|
EnumProps enm(this, iinst, &MODIDX::iuseMin, &BSC_PROP::iuse);
|
|
|
|
while (enm.next()) {
|
|
IPROP iprop = rgUse[enm.iCur].iprop + enm.ipropBase;
|
|
IINST ii = iinstFrEn(rgProp[iprop].en);
|
|
|
|
TYP typ = rgEn[ii].typ;
|
|
|
|
if (typ != INST_TYP_MEMFUNC && typ != INST_TYP_MEMVAR)
|
|
continue;
|
|
|
|
if (!fInstFilter(ii, mbf))
|
|
continue;
|
|
|
|
if (!ppiinst) { *pciinst = 1; return TRUE; }
|
|
rgIinst.append(ii);
|
|
}
|
|
|
|
if (!DupArray(ppiinst, pciinst, rgIinst)) return FALSE;
|
|
|
|
qsort(*ppiinst, *pciinst, sizeof(IINST), CmpIinst);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
// get the array of definitions associated with this instance...
|
|
BOOL Bsc1::getDefArray(IINST iinst, OUT IDEF **ppidef, OUT ULONG *pcidef)
|
|
{
|
|
Array<IDEF> rgIdef;
|
|
|
|
EnumProps enm(this, iinst, &MODIDX::idefMin, &BSC_PROP::idef);
|
|
|
|
while (enm.next()) {
|
|
if (!ppidef) { *pcidef = 1; return TRUE; }
|
|
rgIdef.append(enm.iCur);
|
|
}
|
|
|
|
return DupArray(ppidef, pcidef, rgIdef);
|
|
}
|
|
|
|
BOOL Bsc1::getRefArray(IINST iinst, OUT IREF **ppiref, OUT ULONG *pciref)
|
|
{
|
|
Array<IREF> rgIref;
|
|
|
|
EnumProps enm(this, iinst, &MODIDX::irefMin, &BSC_PROP::iref);
|
|
|
|
while (enm.next()) {
|
|
if (!ppiref) { *pciref = 1; return TRUE; }
|
|
rgIref.append(enm.iCur);
|
|
}
|
|
|
|
return DupArray(ppiref, pciref, rgIref);
|
|
}
|
|
|
|
|
|
// primitives for managing source module contents
|
|
BOOL Bsc1::getModuleContents(IMOD imod, MBF mbf, OUT IINST **ppiinst, OUT ULONG *pciinst)
|
|
{
|
|
IPROP iprop = rgidx[imod].ipropMin;
|
|
IPROP ipropMac = iprop + rghead[imod].cprop;
|
|
|
|
Array<IINST> rgIinst;
|
|
|
|
IDEF idefLast = 0;
|
|
BSC_PROP bp;
|
|
|
|
for (;iprop < ipropMac; iprop++, idefLast = bp.idef) {
|
|
bp = rgProp[iprop];
|
|
|
|
if (bp.idef == idefLast) // check for def'n in this module
|
|
continue;
|
|
|
|
IINST ii = iinstFrEn(bp.en);
|
|
if (!fInstFilter(ii, mbf))
|
|
continue;
|
|
|
|
if (!ppiinst) { *pciinst = 1; return TRUE; }
|
|
rgIinst.append(ii);
|
|
}
|
|
|
|
return DupArray(ppiinst, pciinst, rgIinst);
|
|
}
|
|
|
|
BOOL Bsc1::getModuleByName(SZ szReqd, OUT IMOD *pimod)
|
|
{
|
|
IMOD Lo = 0;
|
|
IMOD Hi = (IMOD)cModules;
|
|
|
|
while (Lo < Hi) {
|
|
IMOD Mid = Lo + (Hi - Lo) / 2; // this way there can be no overflow
|
|
|
|
SZ szCur = szFrNi(rgModNi[Mid]);
|
|
|
|
int Cmp = _tcsicmp(szCur, szReqd);
|
|
|
|
if (Cmp == 0) {
|
|
*pimod = Mid;
|
|
return TRUE;
|
|
}
|
|
|
|
if (Cmp > 0)
|
|
Hi = Mid;
|
|
else
|
|
Lo = Mid + 1;
|
|
}
|
|
|
|
*pimod = imodNil;
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL Bsc1::getAllModulesArray(OUT IMOD **ppimod, OUT ULONG *pcimod)
|
|
{
|
|
*pcimod = cModules;
|
|
|
|
if (!cModules) {
|
|
*ppimod = NULL;
|
|
return TRUE;
|
|
}
|
|
|
|
*ppimod = (IMOD*)malloc(cModules*sizeof(IMOD));
|
|
|
|
if (!*ppimod)
|
|
return FALSE;
|
|
|
|
for (IMOD imod = 0; imod < cModules; imod++)
|
|
(*ppimod)[imod] = imod;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
// call this when a computed array is no longer required
|
|
void Bsc1::disposeArray(void *pAnyArray)
|
|
{
|
|
free(pAnyArray);
|
|
}
|
|
|
|
int Bsc1::cmpStr(SZ sz1, SZ sz2)
|
|
//
|
|
// think of sz1 and sz2 being in a list of things that are sorted
|
|
// case insensitively and then case sensitively within that. This is
|
|
// the case for browser symbols
|
|
//
|
|
// return -1, 0, or 1 if sz1 before, at, or after sz2 in the list
|
|
//
|
|
{
|
|
if (sz1[0] == '?') sz1++;
|
|
if (sz2[0] == '?') sz2++;
|
|
|
|
// do case insensitive compare, these strings are known to contain no DB chars
|
|
int ret = _stricmp(sz1, sz2);
|
|
|
|
// if this is good enough then use it, or if we are only doing
|
|
// a case insensitive search then this is good enough
|
|
|
|
if (ret || !fCase) return ret;
|
|
|
|
// if we must, do the case sensitive compare
|
|
|
|
return strcmp(sz1, sz2);
|
|
}
|
|
|
|
int Bsc1::cmpStrPrefix(SZ szPrefix, SZ szMain)
|
|
// checks to see if szMain begins with szPrefix
|
|
// returns lexical prefix only comparison like cmpStr()
|
|
//
|
|
{
|
|
int lenp = strlen(szPrefix);
|
|
int lenf = strlen(szMain);
|
|
|
|
char buffer[256];
|
|
|
|
assert(lenf < sizeof(buffer));
|
|
strcpy(buffer, szMain);
|
|
|
|
if (szPrefix[0] != '?' && szMain[0] == '?')
|
|
lenp++;
|
|
|
|
if (lenf > lenp)
|
|
buffer[lenp] = '\0';
|
|
|
|
return cmpStr(szPrefix, buffer);
|
|
}
|
|
|
|
|
|
IINST Bsc1::iinstSupSz(SZ szReqd)
|
|
// find the smallest ISYM whose value is greater or equal to the given SZ
|
|
//
|
|
{
|
|
IINST Lo = 0;
|
|
IINST Hi = cEntities;
|
|
|
|
while (Lo < Hi) {
|
|
IINST Mid = Lo + (Hi - Lo) / 2; // this way there can be no overflow
|
|
|
|
SZ szCur = szFrIinst(Mid);
|
|
|
|
int Cmp = cmpStr(szCur, szReqd);
|
|
|
|
if (Cmp >= 0)
|
|
Hi = Mid;
|
|
else
|
|
Lo = Mid + 1;
|
|
}
|
|
|
|
if (Hi == cEntities)
|
|
Hi = iinstNil;
|
|
|
|
return Hi;
|
|
}
|
|
|
|
BOOL Bsc1::findPrefixRange(SZ szprefix, IINST *piinstFirst, IINST *piinstLast)
|
|
// return, if successful, the range of bob's which are prefixed by the
|
|
// zero terminated string in szprefix, the boolean indicates success
|
|
{
|
|
BOOL fCaseSaved = fCase;
|
|
|
|
fCase = FALSE;
|
|
|
|
// init. the range to search
|
|
IINST low = 0;
|
|
IINST high = cEntities;
|
|
|
|
if (*szprefix == '\0') {
|
|
*piinstFirst = low;
|
|
*piinstLast = high - 1;
|
|
fCase = fCaseSaved;
|
|
return TRUE;
|
|
}
|
|
|
|
IINST middle;
|
|
|
|
while (low < high) {
|
|
// get the name of the middle symbol in the range
|
|
middle = low + (high - low) / 2;
|
|
int cmp = cmpStrPrefix(szprefix, szFrIinst(middle));
|
|
|
|
if (cmp == 0)
|
|
break;
|
|
|
|
if (cmp < 0)
|
|
high = middle;
|
|
else
|
|
low = middle + 1;
|
|
}
|
|
|
|
// did we find it?
|
|
if (low >= high) {
|
|
fCase = fCaseSaved;
|
|
return FALSE;
|
|
}
|
|
|
|
// get the range of the instances for this prefix
|
|
IINST curr = middle;
|
|
|
|
assert(!cmpStrPrefix(szprefix, szFrIinst(curr)));
|
|
|
|
while (curr > 0 && !cmpStrPrefix(szprefix, szFrIinst(curr-1)))
|
|
curr--;
|
|
|
|
*piinstFirst = curr;
|
|
curr = middle;
|
|
|
|
while (curr < cEntities-1 && !cmpStrPrefix(szprefix, szFrIinst(curr+1)))
|
|
curr++;
|
|
|
|
*piinstLast = curr;
|
|
|
|
fCase = fCaseSaved;
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL
|
|
Bsc1::fInstFilter(IINST iinst, MBF mbf)
|
|
// return true if the given inst has the required properties
|
|
//
|
|
{
|
|
if (mbf == mbfAll)
|
|
return TRUE;
|
|
|
|
TYP typ = rgEn[iinst].typ;
|
|
|
|
switch (typ) {
|
|
|
|
case INST_TYP_FUNCTION:
|
|
case INST_TYP_LABEL:
|
|
case INST_TYP_PROGRAM:
|
|
case INST_TYP_MEMFUNC:
|
|
return !!(mbf & mbfFuncs);
|
|
|
|
case INST_TYP_PARAMETER:
|
|
case INST_TYP_VARIABLE:
|
|
case INST_TYP_SEGMENT:
|
|
case INST_TYP_GROUP:
|
|
case INST_TYP_MEMVAR:
|
|
return !!(mbf & mbfVars);
|
|
|
|
case INST_TYP_CONSTANT:
|
|
case INST_TYP_MACRO:
|
|
case INST_TYP_ENUMMEM:
|
|
return !!(mbf & mbfMacros);
|
|
|
|
case INST_TYP_TYPEDEF:
|
|
case INST_TYP_ENUMNAM:
|
|
case INST_TYP_UNIONNAM:
|
|
return !!(mbf & mbfTypes);
|
|
|
|
|
|
case INST_TYP_CLASSNAM:
|
|
return !!(mbf & mbfClass);
|
|
|
|
case INST_TYP_STRUCNAM:
|
|
|
|
if ((mbf & (mbfTypes|mbfClass)) == (mbfTypes|mbfClass))
|
|
return TRUE;
|
|
|
|
// test for structs that are being used like classes...
|
|
|
|
ULONG c = 0;
|
|
if ((getBaseArray(iinst, NULL, &c) && c) ||
|
|
(getDervArray(iinst, NULL, &c) && c))
|
|
return !!(mbf & mbfClass);
|
|
|
|
return !!(mbf & mbfTypes);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
SZ Bsc1::formatDname(SZ szDecor)
|
|
{
|
|
#define BUFLEN 250
|
|
static char decorBuf[BUFLEN];
|
|
|
|
if (szDecor[0] != '?')
|
|
return szDecor;
|
|
|
|
__unDName(decorBuf, szDecor, BUFLEN-32, malloc, free,
|
|
UNDNAME_NO_FUNCTION_RETURNS|
|
|
UNDNAME_NO_ALLOCATION_MODEL|
|
|
UNDNAME_NO_ALLOCATION_LANGUAGE|
|
|
UNDNAME_NO_MS_KEYWORDS|
|
|
UNDNAME_NO_MS_THISTYPE|
|
|
UNDNAME_NO_CV_THISTYPE|
|
|
UNDNAME_NO_ACCESS_SPECIFIERS|
|
|
UNDNAME_NO_THROW_SIGNATURES|
|
|
UNDNAME_NO_MEMBER_TYPE|
|
|
UNDNAME_NO_RETURN_UDT_MODEL);
|
|
|
|
szDecor = decorBuf;
|
|
|
|
if (szDecor[0] == ' ')
|
|
szDecor++;
|
|
|
|
if (szDecor[0] == '?' && szDecor[1] == '?' && szDecor[2] == ' ')
|
|
szDecor += 3;
|
|
|
|
return szDecor;
|
|
}
|
|
|
|
IINST Bsc1::iinstFrEn(ENTITY en)
|
|
{
|
|
IINST iinst;
|
|
getIinstByvalue(szFrNi(en.ni), en.typ, en.atr, &iinst);
|
|
return iinst;
|
|
}
|
|
|
|
IINST Bsc1::iinstFrIref(IREF iref)
|
|
{
|
|
IMOD imod = (IMOD)rgRef.isectOfIel(iref);
|
|
return iinstContainingIdx(iref - rgidx[imod].irefMin, &BSC_PROP::iref, imod);
|
|
}
|
|
|
|
IINST Bsc1::iinstFrIdef(IDEF idef)
|
|
{
|
|
IMOD imod = (IMOD)rgDef.isectOfIel(idef);
|
|
return iinstContainingIdx(idef - rgidx[imod].idefMin, &BSC_PROP::idef, imod);
|
|
}
|
|
|
|
IINST Bsc1::iinstContextIref(IREF iref)
|
|
{
|
|
IMOD imod = (IMOD)rgRef.isectOfIel(iref);
|
|
IPROP ipropBase = rgidx[imod].ipropMin;
|
|
|
|
IPROP iprop = ipropContainingIdx(iref - rgidx[imod].irefMin, &BSC_PROP::iref, imod);
|
|
|
|
IPROP ipropBest = ipropNil;
|
|
LINE lineBest = 0;
|
|
LINE lineReqd = rgRef[iref].line;
|
|
|
|
IUBY iuby, iubyMac;
|
|
getIdxRange(imod, iprop, &MODIDX::iuseMin, &BSC_PROP::iuby, iuby, iubyMac);
|
|
|
|
for (;iuby < iubyMac; iuby++) {
|
|
IPROP ipUser = rgUby[iuby].iprop + ipropBase;
|
|
IDEF idef, idefMac;
|
|
getIdxRange(imod, ipUser, &MODIDX::idefMin, &BSC_PROP::idef, idef, idefMac);
|
|
for ( ;idef < idefMac; idef++) {
|
|
LINE line = rgDef[idef].line;
|
|
if (line > lineBest && line <= lineReqd) {
|
|
ipropBest = ipUser;
|
|
lineBest = line;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (ipropBest == ipropNil)
|
|
return iinstNil;
|
|
|
|
return iinstFrEn(rgProp[ipropBest].en);
|
|
}
|
|
|
|
IPROP Bsc1::ipropContainingIdx(ULONG idxReqd, BRIND BSC_PROP::*mIdx, IMOD imod)
|
|
{
|
|
IPROP Lo = rgidx[imod].ipropMin;
|
|
IPROP Hi = Lo + rghead[imod].cprop;
|
|
IPROP ipropMac = Hi;
|
|
|
|
while (Lo < Hi) {
|
|
ULONG Mid = Lo + (Hi - Lo) / 2; // this way there can be no overflow
|
|
|
|
ULONG idx = rgProp[Mid].*mIdx;
|
|
|
|
if (idxReqd < idx)
|
|
Hi = Mid;
|
|
else
|
|
Lo = Mid + 1;
|
|
}
|
|
|
|
if (Hi == ipropMac)
|
|
return ipropNil;
|
|
|
|
return Hi;
|
|
}
|
|
|
|
IINST Bsc1::iinstContainingIdx(ULONG idxReqd, BRIND BSC_PROP::*mIdx, IMOD imod)
|
|
{
|
|
IPROP iprop = ipropContainingIdx(idxReqd, mIdx, imod);
|
|
|
|
if (iprop == ipropNil)
|
|
return iinstNil;
|
|
|
|
return iinstFrEn(rgProp[iprop].en);
|
|
}
|
|
|
|
void Bsc1::getIdxRange(IMOD imod, IPROP iprop, ULONG MODIDX::*mBase, BRIND BSC_PROP::*mIdx, ULONG &iMin, ULONG &iMac)
|
|
{
|
|
ULONG iBase = rgidx[imod].*mBase;
|
|
|
|
if (iprop == rgidx[imod].ipropMin)
|
|
iMin = iBase;
|
|
else
|
|
iMin = iBase + rgProp[iprop-1].*mIdx;
|
|
|
|
iMac = iBase + rgProp[iprop].*mIdx;
|
|
}
|
|
|
|
BOOL Bsc1::getStatistics(struct BSC_STAT *pstat)
|
|
{
|
|
pstat->cMod = cModules;
|
|
pstat->cInst = cEntities;
|
|
pstat->cDef = rgDef.iMac();
|
|
pstat->cRef = rgRef.iMac();
|
|
pstat->cUseLink = rgUse.iMac();
|
|
pstat->cBaseLink = rgBase.iMac();
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL Bsc1::getModuleStatistics(IMOD imod, struct BSC_STAT *pstat)
|
|
{
|
|
BSC_HEAD *ph = &rghead[imod];
|
|
|
|
pstat->cMod = 1;
|
|
pstat->cInst = ph->cprop;
|
|
pstat->cDef = ph->cdef;
|
|
pstat->cRef = ph->cref;
|
|
pstat->cUseLink = ph->cuse;
|
|
pstat->cBaseLink = ph->cbase;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL Bsc1::fCaseSensitive()
|
|
{
|
|
return fCase;
|
|
}
|
|
|
|
BOOL Bsc1::setCaseSensitivity(BOOL fCaseIn)
|
|
{
|
|
fCase = fCaseIn;
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL Bsc1::getAllGlobalsArray(MBF mbf, OUT IINST **ppiinst, OUT ULONG *pciinst)
|
|
{
|
|
precondition(ppiinst);
|
|
precondition(pciinst);
|
|
IINST *rgiinst;
|
|
ULONG cIinst;
|
|
|
|
rgiinst = (IINST*)malloc(cEntities*sizeof(IINST));
|
|
if (!rgiinst) return FALSE;
|
|
|
|
cIinst = 0;
|
|
|
|
for (UINT i = 0; i < cEntities; i++) {
|
|
|
|
// make sure it is the right sort of object
|
|
if (!fInstFilter(i, mbf))
|
|
continue;
|
|
|
|
// then strip out objects with scope
|
|
SZ sz; TYP typ; ATR atr;
|
|
iinstInfo(i, &sz, &typ, &atr);
|
|
|
|
switch (typ) {
|
|
case INST_TYP_MEMVAR:
|
|
case INST_TYP_MEMFUNC:
|
|
case INST_TYP_PARAMETER:
|
|
case INST_TYP_ENUMMEM:
|
|
continue;
|
|
}
|
|
|
|
// these objects are not at global scope
|
|
if (atr & (INST_ATR_LOCAL|INST_ATR_STATIC|INST_ATR_MODULE))
|
|
continue;
|
|
|
|
rgiinst[cIinst++] = i;
|
|
}
|
|
|
|
*ppiinst = rgiinst;
|
|
*pciinst = cIinst;
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL Bsc1::getAllGlobalsArray(MBF mbf, OUT IinstInfo **ppiinstinfo, OUT ULONG *pciinst)
|
|
{
|
|
// NYI
|
|
precondition (FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
SZ Bsc1::getParams (IINST iinst)
|
|
{
|
|
static char buf[2];
|
|
return buf;
|
|
}
|
|
|
|
USHORT Bsc1::getNumParam (IINST iinst)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
SZ Bsc1::getParam (IINST iinst, USHORT index)
|
|
{
|
|
static char buf[2];
|
|
return buf;
|
|
}
|
|
|
|
SZ Bsc1::getType (IINST iinst)
|
|
// get return type/variable type
|
|
{
|
|
static char buf[2];
|
|
return buf;
|
|
}
|
|
|
|
BOOL Bsc1::regNotify (pfnNotifyChange pNotify)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL Bsc1::regNotify ()
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL Bsc1::getQ (NiQ ** ppQ, ULONG * pcQ)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL Bsc1::checkParams (IINST iinst, SZ * pszParam, ULONG cParam)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL Bsc1::fHasMembers (IINST iinst, MBF mbf)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL Bsc1::fHasDefsOrRefs(IINST iinst)
|
|
{
|
|
IMOD imod;
|
|
BYTE mask;
|
|
int ib;
|
|
IPROP iprop;
|
|
ENTITY en;
|
|
ULONG iMac;
|
|
ULONG iCur;
|
|
|
|
en = rgEn[iinst];
|
|
|
|
for (imod = 0; imod < cModules ; imod++) {
|
|
|
|
NI niMax = rghead[imod].niMax;
|
|
if (en.ni > niMax) continue;
|
|
|
|
MaskFrNi(en.ni, niMax, CB_BITS_NI, &ib, &mask);
|
|
|
|
if (!(rghead[imod].bitsNi[ib]&mask)) continue;
|
|
|
|
if ((iprop = ipropFrEn(en, imod)) == ipropNil) continue;
|
|
|
|
// check for a definition
|
|
getIdxRange(imod, iprop, &MODIDX::idefMin, &BSC_PROP::idef, iCur, iMac);
|
|
if (iCur != iMac) return TRUE;
|
|
|
|
// check for a reference
|
|
getIdxRange(imod, iprop, &MODIDX::irefMin, &BSC_PROP::iref, iCur, iMac);
|
|
if (iCur != iMac) return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL Bsc1::niFrIinst (IINST iinst, NI *ni)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL Bsc1::lock ()
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
BOOL Bsc1::unlock ()
|
|
{
|
|
return FALSE;
|
|
}
|