// // // mbRWBSC.C - Write .BSC Source Data Base file from various lists. // // #define LINT_ARGS #include #include #include #include "sbrfdef.h" #include "mbrmake.h" #include "sbrbsc.h" #include "mbrcache.h" // prototypes // static void pascal WriteBSCHeader (void); static void pascal WriteAtoms (void); static void pascal WriteMods (void); static void pascal WriteModSyms (void); static void pascal WriteSyms (void); static void pascal WriteProps (void); static void pascal WriteRefs (void); static void pascal WriteDefs (void); static void pascal WriteCals (void); static void pascal WriteCbys (void); static void pascal WriteSbrInfo (void); static void pascal IndexTree (void); static void pascal BSCWrite (LPV lpv, WORD cch); static void pascal BSCWriteLsz (LSZ lsz); // #define BSCOut(v) BSCWrite(&(v), sizeof(v)) static WORD CntAtomPage; // count of Atom pages static WORD AtomCnt = 0; static WORD unknownModName; // UNKNOWN module idx static WORD ModSymCnt = 0; // count of modsyms static WORD SymCnt = 0; // count of symbols static WORD PropCnt = 0; // count of props static DWORD RefCnt = 0; // count of refs static WORD DefCnt = 0; // count of defs static WORD CbyCnt = 0; // count of use half of above static WORD CalCnt = 0; // count of used by half of above static DWORD lbModList; // offset to Module list static DWORD lbModSymList; // offset to ModSym list static DWORD lbSymList; // offset to Symbol list static DWORD lbPropList; // offset to Property list static DWORD lbRefList; // offset to Reference list static DWORD lbDefList; // offset to Definition list static DWORD lbCalList; // offset to Call/used list static DWORD lbCbyList; // offset to Call/used list static DWORD lbAtomCache; // offset to Sym Atom cache static DWORD lbSbrList; // offset to Sbr file names extern char far *GetAtomCache (WORD); void WriteBSC (char *OutputFileName) // Write .BSC Source Data Base // { OutFile = fopen(OutputFileName, "wb"); if (OutFile == NULL) { Error(ERR_OPEN_FAILED, OutputFileName); } // // no backing out from here -- if we fail we must delete the database // fOutputBroken = TRUE; WriteBSCHeader(); // save space for header WriteAtoms(); // sort and write atom cache IndexTree(); // xlate pointers to indices BldModSymList(); // Build module symbol list SetVMClient(VM_EMIT_TREE); unknownModName = gSYM(vaUnknownSym).isym; // record UNKNOWN index WriteMods(); // output modules WriteModSyms(); // output module symbol lists WriteSyms(); // output all symbols WriteProps(); // output all prop headers WriteRefs(); // output all refs WriteDefs(); // output all defs WriteCals(); // output all uses/calls WriteCbys(); // output all UBY/CBY WriteSbrInfo(); // output the SBR file names if (fseek(OutFile, 0L, SEEK_SET)) // Beginning of file SeekError (OutputFileName); WriteBSCHeader (); // output .BSC header fclose(OutFile); // // we're all done --- it's a keeper! // fOutputBroken = FALSE; SetVMClient(VM_MISC); if (OptV) { printf ("%u\tModules\n", ModCnt); printf ("%u\tSymbols\n", SymCnt); printf ("%u\tDefinitions\n", DefCnt); printf ("%u\tReferences\n", RefCnt); printf ("%u\tCalls/Uses\n", CalCnt); printf ("%u\tCalled by/Used by\n", CbyCnt); #ifdef DEBUG printf ("\n"); printf ("%u\tTotal ModSyms\n", ModSymCnt); printf ("%u\tTotal Properties\n", PropCnt); printf ("%u\tLast Atom page \n", AtomCnt); printf ("\n"); printf ("%lu\tBase of AtomCache\n", lbAtomCache); printf ("%lu\tBase of ModList\n", lbModList); printf ("%lu\tBase of ModSymList\n", lbModSymList); printf ("%lu\tBase of SymList\n", lbSymList); printf ("%lu\tBase of PropList\n", lbPropList); printf ("%lu\tBase of RefList\n", lbRefList); printf ("%lu\tBase of DefList\n", lbDefList); printf ("%lu\tBase of CalList\n", lbCalList); printf ("%lu\tBase of CbyList\n", lbCbyList); #endif } } static void pascal WriteBSCHeader () // Write .BSC header, counts, and table offsets. // { BYTE ver; // version num // output BSC version (major and minor) ver = BSC_MAJ; BSCOut(ver); // major ver ver = BSC_MIN; BSCOut(ver); // minor ver ver = BSC_UPD; BSCOut(ver); // update ver BSCOut(fCase); // case sensitive BSCOut(MaxSymLen); // biggest symbol allowed BSCOut(unknownModName); // UNKNOWN idx // output counts (sizes) of each data area BSCOut(ModCnt); BSCOut(ModSymCnt); BSCOut(SymCnt); BSCOut(PropCnt); BSCOut(RefCnt); BSCOut(DefCnt); BSCOut(CalCnt); BSCOut(CbyCnt); // last page # BSCOut(CntAtomPage); // last page size BSCOut(AtomCnt); // output BSC data area offsets BSCOut(lbModList); BSCOut(lbModSymList); BSCOut(lbSymList); BSCOut(lbPropList); BSCOut(lbRefList); BSCOut(lbDefList); BSCOut(lbCalList); BSCOut(lbCbyList); BSCOut(lbAtomCache); BSCOut(lbSbrList); } static void pascal WriteAtoms () // Write a sorted version of the symbol Atom Cache to the .BSC file by walking // the sorted symbol subscript array // { WORD i; int Atomlen; LPCH lpchAtoms; LSZ lszAtom; VA vaSym; SetVMClient(VM_EMIT_ATOMS); lpchAtoms = LpvAllocCb(ATOMALLOC); lbAtomCache = ftell(OutFile); // offset to text of symbols for (i=0; i < cAtomsMac; i++) { vaSym = rgvaSymSorted[i]; if (vaSym == vaNil) continue; gSYM(vaSym); lszAtom = gTEXT(cSYM.vaNameText); Atomlen = strlen(lszAtom); // write Atom page if not enough room // if (Atomlen + AtomCnt + 1 > ATOMALLOC) { if (AtomCnt < ATOMALLOC) memset(lpchAtoms + AtomCnt, 0, ATOMALLOC - AtomCnt); if ((fwrite (lpchAtoms, ATOMALLOC, 1, OutFile)) != 1) WriteError (OutputFileName); CntAtomPage++; AtomCnt = 0; } strcpy(lpchAtoms + AtomCnt, lszAtom); // copy Atom cSYM.vaNameText = (PVOID)(((long)CntAtomPage << 16) | (AtomCnt)); pSYM(vaSym); AtomCnt += Atomlen + 1; // force to even value if (AtomCnt & 1) lpchAtoms[AtomCnt++] = 0; } // write last Atom page // if (AtomCnt) if ((fwrite (lpchAtoms, AtomCnt, 1, OutFile)) != 1) WriteError (OutputFileName); // free all the memory for the atom cache, we no longer need it fflush (OutFile); FreeLpv(lpchAtoms); SetVMClient(VM_MISC); } static void pascal WriteMods() // write out the list of modules // // compute the MODSYM indices as we do this // { MODLIST bmod; VA vaMod; WORD i; ModSymCnt = 0; lbModList = ftell(OutFile); // offset to Module list for (i = cSymbolsMac; i < cAtomsMac; i++) { gSYM(rgvaSymSorted[i]); vaMod = cSYM.vaFirstProp; // points back to module, honest! gMOD(vaMod); bmod.ModName = gSYM(cMOD.vaNameSym).isym; // module name idx ModSymCnt += cMOD.csyms; bmod.mSymEnd = ModSymCnt; // last ModSym idx +1 BSCOut(bmod); } } static void pascal WriteModSyms() // write out the list of modsyms // { MODSYMLIST bmodsym; VA vaMod, vaModSym; WORD i; lbModSymList = ftell(OutFile); // offset to ModSym list for (i = cSymbolsMac; i < cAtomsMac; i++) { gSYM(rgvaSymSorted[i]); vaMod = cSYM.vaFirstProp; // points back to module, honest! gMOD(vaMod); vaModSym = cMOD.vaFirstModSym; while (vaModSym) { gMODSYM(vaModSym); // Symbol Property idx bmodsym.ModSymProp = gPROP(cMODSYM.vaFirstProp).iprp; BSCOut(bmodsym); vaModSym = cMODSYM.vaNextModSym; } } } static void pascal WriteSyms() // write out the list of SYMs // { SYMLIST bsym; VA vaSym; WORD i; lbSymList = ftell(OutFile); // offset to Symbol list PropCnt = 0; for (i=0; i < cAtomsMac; i++) { vaSym = rgvaSymSorted[i]; if (vaSym == vaNil) continue; gSYM(vaSym); PropCnt += cSYM.cprop; bsym.PropEnd = PropCnt; // last Prop idx +1 bsym.Atom = (WORD)((long)cSYM.vaNameText & 0xffff); // Atom cache offset bsym.Page = (WORD)((long)cSYM.vaNameText >> 16); // Atom cache page BSCOut(bsym); } } static void pascal WriteProps () // write out the list of PROPS to the database // // the number of definitions (DefCnt), references (RefCnt), // calls (CalCnt) and called-by (CbyCnt) items are computed at this time // // Each PROP is assigned numbers for its associated objects // { PROPLIST bprop; VA vaSym, vaProp; WORD i; lbPropList = ftell(OutFile); // offset to Property list DefCnt = 0; RefCnt = 0L; CalCnt = 0; CbyCnt = 0; for (i=0; i < cSymbolsMac; i++) { vaSym = rgvaSymSorted[i]; if (vaSym == vaNil) continue; vaProp = gSYM(vaSym).vaFirstProp; while (vaProp) { gPROP(vaProp); gSYM(cPROP.vaNameSym); bprop.PropName = cSYM.isym; // Symbol idx bprop.PropAttr = cPROP.sattr; // Property Attribute DefCnt += CItemsList(cPROP.vaDefList); bprop.DefEnd = DefCnt; // last Definition idx +1 RefCnt += cPROP.cref; bprop.RefEnd = RefCnt; // last Reference idx +1 CalCnt += CItemsList(cPROP.vaCalList); bprop.CalEnd = CalCnt; // last Calls/uses idx +1 CbyCnt += CItemsList(cPROP.vaCbyList); bprop.CbyEnd = CbyCnt; // last Called by/used by idx +1 BSCOut(bprop); vaProp = cPROP.vaNextProp; } } } static void pascal WriteRefs() // write out the list of references // { REFLIST bref; VA vaSym, vaProp, vaRef; WORD i; lbRefList = ftell(OutFile); // offset to Reference list for (i=0; i < cSymbolsMac; i++) { vaSym = rgvaSymSorted[i]; if (vaSym == vaNil) continue; vaProp = gSYM(vaSym).vaFirstProp; while (vaProp) { gPROP(vaProp); vaRef = VaFrVp(cPROP.vpFirstRef); while (vaRef) { gREF(vaRef); gSYM(VaFrVp(cREF.vpFileSym)); bref.RefNam = cSYM.isym; // Symbol idx bref.RefLin = cREF.reflin; // Symbol lin bref.isbr = cREF.isbr; // owner BSCOut(bref); vaRef = VaFrVp(cREF.vpNextRef); } vaProp = cPROP.vaNextProp; } } } static void pascal WriteDefs() // write out the list of defintions // { REFLIST bdef; WORD i; VA vaProp, vaSym; lbDefList = ftell(OutFile); // offset to Definition list for (i=0; i < cSymbolsMac; i++) { vaSym = rgvaSymSorted[i]; if (vaSym == vaNil) continue; vaProp = gSYM(vaSym).vaFirstProp; while (vaProp) { gPROP(vaProp); ENM_LIST (cPROP.vaDefList, DEF) gSYM(cDEF.vaFileSym); bdef.RefNam = cSYM.isym; // Symbol idx bdef.RefLin = cDEF.deflin; // Symbol lin bdef.isbr = cDEF.isbr; // owner BSCOut(bdef); ENM_END vaProp = cPROP.vaNextProp; } } } static void pascal WriteCals() // write out the list of uses (CALs) items // { USELIST buse; PROP prop; VA vaSym, vaProp; WORD i; lbCalList = ftell(OutFile); // offset to CAL list for (i=0; i < cSymbolsMac; i++) { vaSym = rgvaSymSorted[i]; if (vaSym == vaNil) continue; vaProp = gSYM(vaSym).vaFirstProp; while (vaProp) { prop = gPROP(vaProp); ENM_LIST(prop.vaCalList, CAL) gPROP(cCAL.vaCalProp); buse.UseProp = cPROP.iprp; // property idx buse.UseCnt = (BYTE) cCAL.calcnt; // use count buse.isbr = cCAL.isbr; // owner BSCOut(buse); ENM_END vaProp = prop.vaNextProp; } } BSCOut(buse); // Pad } static void pascal WriteCbys() // write out the list of used-by (CBY) items // { USELIST buse; PROP prop; VA vaSym, vaProp; WORD i; lbCbyList = ftell(OutFile); // offset to CBY list for (i=0; i < cSymbolsMac; i++) { vaSym = rgvaSymSorted[i]; if (vaSym == vaNil) continue; vaProp = gSYM(vaSym).vaFirstProp; while (vaProp) { prop = gPROP(vaProp); ENM_LIST(prop.vaCbyList, CBY) gPROP(cCBY.vaCbyProp); buse.UseProp = cPROP.iprp; // property idx buse.UseCnt = (BYTE) cCBY.cbycnt; // use count buse.isbr = cCBY.isbr; // owner BSCOut(buse); ENM_END vaProp = prop.vaNextProp; } } BSCOut(buse); // Pad } static void pascal WriteSbrInfo() // write out the names of the .sbr files in the correct order // { VA vaSbr; WORD isbr; VA *rgVaSbr; lbSbrList = ftell(OutFile); rgVaSbr = (VA *)LpvAllocCb(SbrCnt * (WORD)sizeof(VA)); for (isbr = 0; isbr < SbrCnt; isbr++) rgVaSbr[isbr] = vaNil; vaSbr = vaRootSbr; while (vaSbr) { gSBR(vaSbr); if (cSBR.isbr != -1) rgVaSbr[cSBR.isbr] = vaSbr; vaSbr = cSBR.vaNextSbr; } for (isbr = 0; isbr < SbrCnt; isbr++) { if (rgVaSbr[isbr] != vaNil) { gSBR(rgVaSbr[isbr]); BSCWriteLsz(cSBR.szName); } } BSCWriteLsz(""); } static void pascal IndexTree () // Walk all the list of all symbols and index each prop as we find it // at this point we also count the total number of defs + refs to // make sure that we can actually create this database // { VA vaSym, vaProp; DWORD cdefs = 0; DWORD crefs = 0; DWORD ccals = 0; DWORD ccbys = 0; WORD i; SetVMClient(VM_INDEX_TREE); SymCnt = 0; PropCnt = 0; for (i=0; i < cAtomsMac; i++) { vaSym = rgvaSymSorted[i]; if (vaSym == vaNil) continue; gSYM(vaSym); cSYM.isym = SymCnt++; // Symbol index pSYM(vaSym); // the vaFirstProp field is used for something else in module symbols if (cSYM.cprop) vaProp = cSYM.vaFirstProp; else vaProp = vaNil; while (vaProp) { gPROP(vaProp); cPROP.iprp = PropCnt++; // Property index cdefs += CItemsList(cPROP.vaDefList); crefs += cPROP.cref; ccals += CItemsList(cPROP.vaCalList); ccbys += CItemsList(cPROP.vaCbyList); pPROP(vaProp); vaProp = cPROP.vaNextProp; } } SymCnt -= ModCnt; // Subtract module names if (cdefs > 0xffffL || crefs > 0xffffffL || ccals > 0xffffL || ccbys > 0xffffL) { if (OptV) { printf ("%u\tModules\n", ModCnt); printf ("%u\tSymbols\n", SymCnt); printf ("%lu\tDefinitions\n", cdefs); printf ("%lu\tReferences\n", crefs); printf ("%lu\tCalls/Uses\n", ccals); printf ("%lu\tCalled by/Used by\n", ccbys); } Error(ERR_CAPACITY_EXCEEDED, ""); } SetVMClient(VM_MISC); } static void pascal BSCWrite(LPV lpv, WORD cch) // write block to the .bsc file // { if (fwrite(lpv, cch, 1, OutFile) != 1) WriteError (OutputFileName); } static void pascal BSCWriteLsz(LSZ lsz) // write a null terminated string to the BSC file // { BSCWrite(lsz, (WORD)(strlen(lsz)+1)); } #ifdef DEBUG void DebugDump() { VA vaMod, vaProp, vaSym; WORD i; vaMod = vaRootMod; printf("Modules:\n"); while (vaMod) { gMOD(vaMod); printf ("\t%s\n", GetAtomStr (cMOD.vaNameSym)); vaMod = cMOD.vaNextMod; } printf ("\nAll Symbols:\n"); for (i=0; i < cAtomsMac; i++) { vaSym = rgvaSymSorted[i]; if (vaSym == vaNil) continue; gSYM(vaSym); // the vaFirstProp field is used for something else in module symbols if (cSYM.cprop) vaProp = cSYM.vaFirstProp; else vaProp = vaNil; while (vaProp) { gPROP(vaProp); DebugDumpProp(vaProp); vaProp = gPROP(vaProp).vaNextProp; } } } void DebugDumpProp(VA vaProp) { PROP prop; VA vaRef; gPROP(vaProp); prop = cPROP; printf ("%s ", GetAtomStr (prop.vaNameSym)); printf ("\t\t[%d %d %d %d]\n", CItemsList(prop.vaDefList), prop.cref, CItemsList(prop.vaCalList), CItemsList(prop.vaCbyList) ); ENM_LIST(prop.vaDefList, DEF) printf ("\tdefined in %s(%d) <%d>\n", GetAtomStr (cDEF.vaFileSym), cDEF.deflin, cDEF.isbr ); ENM_END vaRef = VaFrVp(prop.vpFirstRef); while (vaRef) { gREF(vaRef); printf ("\trefer'd in %s(%d) <%d>\n", GetAtomStr ( VaFrVp(cREF.vpFileSym) ), cREF.reflin, cREF.isbr ); vaRef = VaFrVp(cREF.vpNextRef); } ENM_LIST(prop.vaCalList, CAL) printf ("\tcalls/uses %s[%d] <%d>\n", GetAtomStr (gPROP(cCAL.vaCalProp).vaNameSym), cCAL.calcnt, cCAL.isbr ); ENM_END ENM_LIST(prop.vaCbyList, CBY) printf ("\tc-by/u-by %s[%d] <%d>\n", GetAtomStr (gPROP(cCBY.vaCbyProp).vaNameSym), cCBY.cbycnt, cCBY.isbr ); ENM_END } #endif