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