// // readbsc.c -- read in a .BSC file and install in mbrmake's vm space // // Copyright 1988, Microsoft Corporation // // Revision History: // // 13-Aug-1989 rm Extracted from mbrapi.c // #define LINT_ARGS #include "mbrmake.h" #include #include "mbrcache.h" #include "sbrfdef.h" // sbr attributes #include "sbrbsc.h" typedef struct _sbrinfo { WORD fUpdate; WORD isbr; } SI, far *LPSI; // sbr info #define LISTALLOC 50 // Browser max list size typedef WORD IDX; // these will be initialized by the reading of the .bsc file // // fCase; TRUE for case compare // MaxSymLen; longest symbol length // ModCnt; count of modules // SbrCnt; count of sbr files // vaUnknownSym; unknown symbol // vaUnknownMod; unknown module // // static data static BOOL fIncremental; // update will be incremental static BOOL fFoundSBR; // at least .sbr file matched static int fhBSC = 0; // .BSC file handle static IDX Unknown; // UNKNOWN symbol index static WORD ModSymCnt; // count of modsyms static WORD SymCnt; // count of symbols static WORD PropCnt; // count of properties static DWORD RefCnt; // count of references static WORD DefCnt; // count of definitions static WORD CalCnt; // count of calls static WORD CbyCnt; // count of called bys static WORD lastAtomPage; // last atom page # static WORD lastAtomCnt; // last atom page size static WORD cbModSymCnt; // size of list of modsyms static WORD cbSymCnt; // size of list of symbols static WORD cbPropCnt; // size of list of properties static WORD cbRefCnt; // size of list of references static WORD cbDefCnt; // size of list of definitions static WORD cbCalCnt; // size of list of calls static WORD cbCbyCnt; // size of list of called bys static WORD MaxModSymCnt; // max list of modsyms static WORD MaxSymCnt; // max list of symbols static WORD MaxPropCnt; // max list of properties static WORD MaxRefCnt; // max list of references static WORD MaxDefCnt; // max list of definitions static WORD MaxCalCnt; // max list of calls static WORD MaxCbyCnt; // max list of called bys static DWORD lbModSymList; // modsym list file start static DWORD lbSymList; // symbol list file start static DWORD lbPropList; // property list file start static DWORD lbRefList; // reference list file start static DWORD lbDefList; // defintion list file start static DWORD lbCalList; // call list file start static DWORD lbCbyList; // called by list file start static DWORD lbSbrList; // sbr list file start static DWORD lbAtomCache; // atom cache file start static WORD CurModSymPage = 0; // Current page of modsyms static WORD CurSymPage = 0; // Current page of symbols static WORD CurPropPage = 0; // Current page of properties static WORD CurRefPage = 0; // Current page of references static WORD CurDefPage = 0; // Current page of defintions static WORD CurCalPage = 0; // Current page of calls static WORD CurCbyPage = 0; // Current page of called bys static LSZ lszBSCName = NULL; // name of .bsc file static MODLIST far *pfModList; // module list cache start static MODSYMLIST far *pfModSymList; // modsym list cache start static SYMLIST far *pfSymList; // symbol list cache start static PROPLIST far *pfPropList; // property list cache start static REFLIST far *pfRefList; // reference list cache start static REFLIST far *pfDefList; // def'n list cache start static USELIST far *pfCalList; // calls list cache start static USELIST far *pfCbyList; // call bys list cache start static WORD AtomPageTblMac; // last cache page used static CACHEPAGE AtomPageTbl[MAXATOMPAGETBL]; // Atom Cache table #define bMOD(imod) (pfModList[imod]) #define bMODSYM(isym) (pfModSymList[ModSymPAGE(isym)]) #define bSYM(isym) (pfSymList[SymPAGE(isym)]) #define bPROP(iprop) (pfPropList[PropPAGE(iprop)]) #define bREF(iref) (pfRefList[RefPAGE(iref)]) #define bDEF(idef) (pfDefList[DefPAGE(idef)]) #define bCAL(iuse) (pfCalList[CalPAGE(iuse)]) #define bCBY(iuse) (pfCbyList[CbyPAGE(iuse)]) #define bUSE(iuse) (pfCalList[CalPAGE(iuse)]) #define bUBY(iuse) (pfCbyList[CbyPAGE(iuse)]) #define BSCIn(v) ReadBSC(&v, sizeof(v)) // prototypes // static VOID GetBSCLsz(LSZ lsz); static VOID GetBSC (DWORD lpos, LPV lpv, WORD cb); static VOID ReadBSC(LPV lpv, WORD cb); static IDX SwapPAGE (DWORD, LPV, WORD, WORD, WORD *, DWORD); static LPCH GetAtomCache (WORD); static WORD ModSymPAGE(WORD idx); static WORD SymPAGE(WORD idx); static WORD PropPAGE(WORD idx); static WORD RefPAGE(DWORD idx); static WORD DefPAGE(WORD idx); static WORD CalPAGE(WORD idx); static WORD CbyPAGE(WORD idx); static LSZ LszNameFrIsym(WORD isym); static LPSI LpsiCreate(VOID); static VOID GetBSCLsz(LSZ lsz) // read a null terminated string from the current position in the BSC file // { for (;;) { if (read(fhBSC, lsz, 1) != 1) ReadError(lszBSCName); if (*lsz++ == 0) return; } } static VOID ReadBSC(LPV lpv, WORD cb) // read a block of data from the BSC file // // the requested number of bytes MUST be present // { if (read(fhBSC, lpv, cb) != (int)cb) ReadError(lszBSCName); } static VOID GetBSC(DWORD lpos, LPV lpv, WORD cb) // Read a block of the specified size from the specified position // // we have to be tolerant of EOF here because the swapper might ask // for a whole block when only block when only part of a block is actually // is actually present // { if (lseek(fhBSC, lpos, SEEK_SET) == -1) SeekError(lszBSCName); if (read(fhBSC, lpv, cb) == -1) ReadError(lszBSCName); } static IDX SwapPAGE (DWORD lbuflist, LPV pfTABLE, WORD tblsiz, /* */ WORD lstsiz, WORD * pcurpage, DWORD idx) // SwapPAGE - Swap in the table page for the table pfTABLE[idx] // and return the table's new index in the page. { WORD page; IDX newidx; page = (WORD)(idx / lstsiz); newidx = (WORD)(idx % lstsiz); if (page == *pcurpage) return newidx; GetBSC(lbuflist+((long)tblsiz*(long)page), pfTABLE, tblsiz); *pcurpage = page; return newidx; } static IDX ModSymPAGE (IDX idx) // Swap in the ModSym page for ModSym[idx] // return the ModSym's index in the page. // { return SwapPAGE (lbModSymList, pfModSymList, cbModSymCnt, MaxModSymCnt, &CurModSymPage, (DWORD)idx); } static IDX SymPAGE (IDX idx) // Swap in the Symbol page for symbol[idx] // return the Symbol's index in the page. // { return SwapPAGE (lbSymList, pfSymList, cbSymCnt, MaxSymCnt, &CurSymPage, (DWORD)idx); } static IDX PropPAGE (IDX idx) // Swap in the Property page for Property[idx] // return the Property's index in the page. // { return SwapPAGE (lbPropList, pfPropList, cbPropCnt, MaxPropCnt, &CurPropPage, (DWORD)idx); } static IDX RefPAGE (DWORD idx) // Swap in the Reference page for Reference[idx] (ref/def) // return the Reference's index in the page. // { return SwapPAGE (lbRefList, pfRefList, cbRefCnt, MaxRefCnt, &CurRefPage, idx); } static IDX DefPAGE (IDX idx) // Swap in the Reference page for Defintions[idx] (ref/def) // return the Reference's index in the page. // { return SwapPAGE (lbDefList, pfDefList, cbDefCnt, MaxDefCnt, &CurDefPage, (DWORD)idx); } static IDX CalPAGE (IDX idx) // Swap in the Usage page for Usage[idx] (cal/cby) // and return the Usage's index in the page. // { return SwapPAGE (lbCalList, pfCalList, cbCalCnt, MaxCalCnt, &CurCalPage, (DWORD)idx); } static IDX CbyPAGE (IDX idx) // Swap in the Usage page for Usage[idx] (cal/cby) // and return the Usage's index in the page. // { return SwapPAGE (lbCbyList, pfCbyList, cbCbyCnt, MaxCbyCnt, &CurCbyPage, (DWORD)idx); } static LPCH GetAtomCache (WORD Page) // load the requested page into the cache // { WORD ipg; WORD pagesize; LPCH pfAtomCsave; for (ipg = 0; ipg < AtomPageTblMac; ipg++) { if (AtomPageTbl[ipg].uPage == Page) return AtomPageTbl[ipg].pfAtomCache; } if (ipg == AtomPageTblMac && ipg != MAXATOMPAGETBL) AtomPageTblMac++; pfAtomCsave = AtomPageTbl[MAXATOMPAGETBL-1].pfAtomCache; for (ipg = MAXATOMPAGETBL-1; ipg; ipg--) AtomPageTbl[ipg] = AtomPageTbl[ipg-1]; // move up AtomPageTbl[0].pfAtomCache = pfAtomCsave; AtomPageTbl[0].uPage = Page; if (Page == lastAtomPage) pagesize = lastAtomCnt; else pagesize = ATOMALLOC; GetBSC(lbAtomCache+ATOMALLOC*(long)Page, AtomPageTbl[0].pfAtomCache, pagesize); return AtomPageTbl[0].pfAtomCache; } static LSZ LszNameFrIsym (IDX isym) // Swap in the Atom page for the symbol isym // return the atom's address in the page. // { SYMLIST sym; sym = bSYM(isym); return GetAtomCache (sym.Page) + sym.Atom; } VOID CloseBSC() // close database and free as much memory as possible // return TRUE iff successful. // { int i; if (fhBSC) { // if open then close, & free memory FreeLpv (pfModList); // module table FreeLpv (pfModSymList); // modsym table FreeLpv (pfSymList); // symbol table FreeLpv (pfPropList); // property table FreeLpv (pfRefList); // reference table FreeLpv (pfDefList); // definition table FreeLpv (pfCalList); // call table FreeLpv (pfCbyList); // called by table for (i=0; i < MAXATOMPAGETBL; i++) FreeLpv (AtomPageTbl[i].pfAtomCache); // dispose Atom Cache close (fhBSC); } } BOOL FOpenBSC (LSZ lszName) // Open the specified data base. // Allocate buffers for cache areas // Initialize the data cache from the data base. // // Return TRUE iff successful, FALSE if database can't be read // { int i; WORD pagesize; BYTE MajorVer; // .bsc version (major) BYTE MinorVer; // .bsc version (minor) BYTE UpdatVer; // .bsc version (updat) WORD MaxModCnt; // max list of modules WORD cbModCnt; // size of list of modules DWORD lbModList; // module list file start lszBSCName = lszName; fhBSC = open(lszBSCName, O_BINARY|O_RDONLY); // if the .bsc file doesn't exist then we don't do any work // this is the cold compile case // if (fhBSC == -1) return FALSE; // read and check BSC version (major, minor and update) BSCIn(MajorVer); BSCIn(MinorVer); BSCIn(UpdatVer); #ifdef DEBUG printf("Browser Data Base: %s ver %d.%d.%d\n\n", lszBSCName, MajorVer, MinorVer, UpdatVer); #endif if ((MajorVer != BSC_MAJ) || (MinorVer != BSC_MIN) || (UpdatVer != BSC_UPD)) return FALSE; // we will be attempting an incremental update fIncremental = TRUE; // read Case sense switch, max symbol length and Unknown module id BSCIn(fCase); BSCIn(MaxSymLen); BSCIn(Unknown); // read counts (sizes) of each data area BSCIn(ModCnt); BSCIn(ModSymCnt); BSCIn(SymCnt); BSCIn(PropCnt); BSCIn(RefCnt); BSCIn(DefCnt); BSCIn(CalCnt); BSCIn(CbyCnt); BSCIn(lastAtomPage); BSCIn(lastAtomCnt); // read BSC data area offsets BSCIn(lbModList); BSCIn(lbModSymList); BSCIn(lbSymList); BSCIn(lbPropList); BSCIn(lbRefList); BSCIn(lbDefList); BSCIn(lbCalList); BSCIn(lbCbyList); BSCIn(lbAtomCache); BSCIn(lbSbrList); // determine data cache area sizes #define MIN(a,b) ((a)>(b) ? (b) : (a)) MaxModCnt = ModCnt; // max list of modules MaxModSymCnt = MIN(ModSymCnt , LISTALLOC); // max list of modsyms MaxSymCnt = MIN(SymCnt+ModCnt, LISTALLOC); // max list of symbols MaxPropCnt = MIN(PropCnt , LISTALLOC); // max list of props MaxRefCnt = (WORD)MIN(RefCnt, (long)LISTALLOC); // max list of refs MaxDefCnt = MIN(DefCnt , LISTALLOC); // max list of defs MaxCalCnt = MIN(CalCnt , LISTALLOC); // max list of cals MaxCbyCnt = MIN(CbyCnt , LISTALLOC); // max list of cbys cbModCnt = sizeof (MODLIST) * MaxModCnt; // size of mods list cbModSymCnt = sizeof (MODSYMLIST) * MaxModSymCnt; // size of modsyms list cbSymCnt = sizeof (SYMLIST) * MaxSymCnt; // size of syms list cbPropCnt = sizeof (PROPLIST) * MaxPropCnt; // size of props list cbRefCnt = sizeof (REFLIST) * MaxRefCnt; // size of refs list cbDefCnt = sizeof (REFLIST) * MaxDefCnt; // size of defs list cbCalCnt = sizeof (USELIST) * MaxCalCnt; // size of cals list cbCbyCnt = sizeof (USELIST) * MaxCbyCnt; // size of cbys list // Allocate data cache pfModList = LpvAllocCb(cbModCnt); pfModSymList = LpvAllocCb(cbModSymCnt); pfSymList = LpvAllocCb(cbSymCnt); pfPropList = LpvAllocCb(cbPropCnt); pfRefList = LpvAllocCb(cbRefCnt); pfDefList = LpvAllocCb(cbDefCnt); pfCalList = LpvAllocCb(cbCalCnt); pfCbyList = LpvAllocCb(cbCbyCnt); for (i=0; i < MAXATOMPAGETBL; i++) { AtomPageTbl[i].uPage = 0; AtomPageTbl[i].pfAtomCache = LpvAllocCb(ATOMALLOC); } AtomPageTblMac = 0; // last cache page used AtomPageTbl[0].uPage = 65535; // read data areas if (lastAtomPage == 0) pagesize = lastAtomCnt; else pagesize = ATOMALLOC; GetBSC(lbModList, pfModList, cbModCnt); // Init Mod cache GetBSC(lbModSymList, pfModSymList, cbModSymCnt); // Init ModSym cache GetBSC(lbSymList, pfSymList, cbSymCnt); // Init Sym cache GetBSC(lbPropList, pfPropList, cbPropCnt); // Init Prop cache GetBSC(lbRefList, pfRefList, cbRefCnt); // Init Ref cache GetBSC(lbDefList, pfDefList, cbDefCnt); // Init Def cache GetBSC(lbCalList, pfCalList, cbCalCnt); // Init Cal cache GetBSC(lbCbyList, pfCbyList, cbCbyCnt); // Init Cby cache GetAtomCache (0); // Init Atom cache return TRUE; } VOID InstallBSC() // Install the currently open BSC into the mbrmake lists // { IDX iprop, imod, isym, idef, ical, icby, isbr, iFirstFileSym; VA vaSym, vaProp, vaRef, vaFileSym, vaMod; DWORD iref; PROPLIST prop, prop0; MODLIST mod; DEF def; CAL cal; CBY cby; VA *rgVaProp; // preallocated array of PROPs VA *rgVaFileSym; // cached SYMs for the filenames BYTE *rgFModUsed; // is this module used? SI *mpIsbrSi; rgVaProp = (VA *)LpvAllocCb(PropCnt * sizeof(VA)); rgVaFileSym = (VA *)LpvAllocCb(ModCnt * sizeof(VA)); rgFModUsed = (BYTE *)LpvAllocCb(ModCnt * sizeof(BYTE)); // make the SBR info for this BSC file mpIsbrSi = LpsiCreate(); // this relies on the fact that all the SYMs for the files are together // (they're after all the SYMs for the variables) iFirstFileSym = bMOD(0).ModName; for (iprop = 0; iprop < PropCnt; iprop++) rgVaProp[iprop] = VaAllocGrpCb(grpProp, sizeof(PROP)); for (imod = 0; imod < ModCnt; imod++) { mod = bMOD(imod); vaCurMod = VaAllocGrpCb(grpMod, sizeof(MOD)); gMOD(vaCurMod); cMOD.vaFirstModSym = vaNil; cMOD.csyms = 0; cMOD.vaNameSym = MbrAddAtom (LszNameFrIsym (mod.ModName), TRUE); cMOD.vaNextMod = vaRootMod; pMOD(vaCurMod); rgVaFileSym[imod] = cMOD.vaNameSym; rgFModUsed[imod] = 0; vaRootMod = vaCurMod; if (Unknown == mod.ModName) { vaUnknownSym = cMOD.vaNameSym; vaUnknownMod = vaCurMod; } gSYM(cMOD.vaNameSym).vaFirstProp = vaCurMod; // store ptr to MOD pSYM(cMOD.vaNameSym); } for (isym = 0; isym < SymCnt; isym++) { vaSym = MbrAddAtom(LszNameFrIsym(isym), FALSE); iprop = isym ? bSYM((IDX)(isym-1)).PropEnd : 0; for (; iprop < bSYM(isym).PropEnd; iprop++) { prop = bPROP(iprop); if (iprop) prop0 = bPROP((IDX)(iprop-1)); else { prop0.DefEnd = 0L; prop0.RefEnd = 0; prop0.CalEnd = 0; prop0.CbyEnd = 0; } // the properties were preallocated vaProp = rgVaProp[iprop]; gSYM(vaSym); if (cSYM.vaFirstProp == vaNil) cSYM.vaFirstProp = vaProp; else cPROP.vaNextProp = vaProp; cSYM.cprop++; pSYM(vaSym); gPROP(vaProp); cPROP.vaNameSym = vaSym; cPROP.sattr = prop.PropAttr; #ifdef DEBUG if (isym != prop.PropName) printf("\t ERROR property points back to wrong symbol!\n"); // DEBUG #endif for (idef = prop0.DefEnd; idef < prop.DefEnd; idef++) { isbr = bDEF(idef).isbr; // this SBR file is being updated -- ignore incoming info if (isbr == 0xffff || mpIsbrSi[isbr].fUpdate) continue; imod = bDEF(idef).RefNam - iFirstFileSym; def.isbr = mpIsbrSi[isbr].isbr; def.deflin = bDEF(idef).RefLin; def.vaFileSym = rgVaFileSym[imod]; rgFModUsed[imod] = 1; VaAddList(&cPROP.vaDefList, &def, sizeof(def), grpDef); } for (iref = prop0.RefEnd; iref < prop.RefEnd; iref++) { isbr = bREF(iref).isbr; // this SBR file is being updated -- ignore incoming info if (mpIsbrSi[isbr].fUpdate) continue; vaRef = VaAllocGrpCb(grpRef, sizeof(REF)); gREF(vaRef); imod = bREF(iref).RefNam - iFirstFileSym; cREF.isbr = mpIsbrSi[isbr].isbr; cREF.reflin = bREF(iref).RefLin; vaFileSym = rgVaFileSym[imod]; rgFModUsed[imod] = 1; MkVpVa(cREF.vpFileSym, vaFileSym); pREF(vaRef); AddTail (Ref, REF); cPROP.cref++; // count references } for (ical = prop0.CalEnd; ical < prop.CalEnd; ical++) { isbr = bCAL(ical).isbr; // this SBR file is being updated -- ignore incoming info if (mpIsbrSi[isbr].fUpdate) continue; cal.isbr = mpIsbrSi[isbr].isbr; cal.vaCalProp = rgVaProp[bCAL(ical).UseProp]; cal.calcnt = bCAL(ical).UseCnt; VaAddList(&cPROP.vaCalList, &cal, sizeof(cal), grpCal); } for (icby = prop0.CbyEnd; icby < prop.CbyEnd; icby++) { isbr = bCBY(icby).isbr; // this SBR file is being updated -- ignore incoming info if (mpIsbrSi[isbr].fUpdate) continue; cby.isbr = mpIsbrSi[isbr].isbr; cby.vaCbyProp = rgVaProp[bCBY(icby).UseProp]; cby.cbycnt = bCBY(icby).UseCnt; VaAddList(&cPROP.vaCbyList, &cby, sizeof(cby), grpCby); } pPROP(vaProp); } } for (imod = 0; imod < ModCnt; imod++) { vaMod = gSYM(rgVaFileSym[imod]).vaFirstProp; gMOD(vaMod); if (rgFModUsed[imod] == 0) { cMOD.csyms = 1; // mark this MOD as empty pMOD(vaMod); } } FreeLpv(mpIsbrSi); FreeLpv(rgFModUsed); FreeLpv(rgVaFileSym); FreeLpv(rgVaProp); } static LPSI LpsiCreate() // create the SBR info records for this .BSC file // { SI FAR *mpIsbrSi; LSZ lszSbrName; VA vaSbr; WORD isbr, isbr2; WORD fUpdate; // add the files that are current in the database to the list of .SBR files // lszSbrName = LpvAllocCb(PATH_BUF); lseek(fhBSC, lbSbrList, SEEK_SET); for (isbr = 0;;isbr++) { GetBSCLsz(lszSbrName); if (*lszSbrName == '\0') break; vaSbr = VaSbrAdd(SBR_OLD, lszSbrName); cSBR.isbr = isbr; pSBR(vaSbr); } FreeLpv(lszSbrName); mpIsbrSi = LpvAllocCb(SbrCnt * sizeof(SI)); // allocate and fill in the new table with the base numbers // mark files that are staying and those that are going away // number any new sbr files that we find while doing this. vaSbr = vaRootSbr; while (vaSbr) { gSBR(vaSbr); if (cSBR.isbr == (WORD)-1) { cSBR.isbr = isbr++; pSBR(vaSbr); } if (cSBR.fUpdate == SBR_NEW) Warning(WARN_SBR_TRUNC, cSBR.szName); else if (cSBR.fUpdate & SBR_NEW) fFoundSBR = TRUE; mpIsbrSi[cSBR.isbr].fUpdate = cSBR.fUpdate; vaSbr = cSBR.vaNextSbr; } if (!fFoundSBR) { // all SBR files were not in the database and were truncated. ERROR! Error(ERR_ALL_SBR_TRUNC, ""); } isbr2 = 0; for (isbr = 0; isbr < SbrCnt; isbr++) { fUpdate = mpIsbrSi[isbr].fUpdate; if (fUpdate & SBR_NEW) mpIsbrSi[isbr].isbr = isbr2++; else mpIsbrSi[isbr].isbr = (WORD)-1; if ((fUpdate & SBR_UPDATE) || (fUpdate & SBR_OLD) && (~fUpdate & SBR_NEW)) mpIsbrSi[isbr].fUpdate = TRUE; else mpIsbrSi[isbr].fUpdate = FALSE; } return mpIsbrSi; } VOID NumberSBR() // stub version of LpsiCreate --- call this if FOpenBSC fails to just // assign new numbers to all the .sbr files that are in the list // { VA vaSbr; WORD isbr; // number new sbr files vaSbr = vaRootSbr; isbr = 0; while (vaSbr) { gSBR(vaSbr); #ifdef DEBUG if (cSBR.isbr != (WORD)-1) { printf("Non initialized SBR file encountered\n"); //DEBUG } #endif // if this file is truncated then and there is no // old version of the file then emit a warning about the file // and then an error stating that we are not in incremental mode if (cSBR.fUpdate == SBR_NEW) { Warning(WARN_SBR_TRUNC, cSBR.szName); Error(ERR_NO_INCREMENTAL, ""); } cSBR.isbr = isbr++; pSBR(vaSbr); vaSbr = cSBR.vaNextSbr; } }