windows-nt/Source/XPSP1/NT/sdktools/mep/browser/mbrmake/mbrmake.c
2020-09-26 16:20:57 +08:00

756 lines
17 KiB
C

//
// mbrmake - Source Browser Source Data Base builder
// (C) 1988 By Microsoft
//
// 29-Aug-1989 dw Minor fixes to aid in C 6 conversion
//
//
#define LINT_ARGS
// rjsa #include <signal.h>
#include <process.h>
#include <direct.h>
#include <stdlib.h>
// get version.h from mb
#include "..\..\inc\version.h"
#include "sbrvers.h"
#include "sbrfdef.h"
#include "mbrmake.h"
#include <sys\types.h>
#include <sys\stat.h>
#include <tools.h>
// this fixes the bogosity in config.h that gets included by tools.h
// it will set DEBUG = 0 for a non-debug version...
//
// -rm
#ifdef DEBUG
#if DEBUG == 0
#undef DEBUG
#endif
#endif
static VOID TruncateSBR(char *lszName);
static VOID ProcessSBR(char *lszName);
static VOID MarkNewSBR(char *lszName);
#ifdef DEBUG
WORD near OptD = 0;
#endif
FILE * near streamOut = stdout;
BOOL near OptEs = FALSE; // exclude system files
BOOL near OptEm = FALSE; // exclude macro expansions
BOOL near OptIu = FALSE; // include unreference symbols
BOOL near OptV = FALSE; // verbose output
BOOL near OptN = FALSE; // no incremental behaviour
char near c_cwd[PATH_BUF]; // current working directory
char near patbuf[PATH_BUF];
MOD FAR * near modRes; // VM cache
MODSYM FAR * near modsymRes;
SYM FAR * near symRes;
PROP FAR * near propRes;
DEF FAR * near defRes;
REF FAR * near refRes;
CAL FAR * near calRes;
CBY FAR * near cbyRes;
ORD FAR * near ordRes;
SBR FAR * near sbrRes;
char FAR * near textRes;
OCR FAR * near ocrRes;
BYTE near fCase = FALSE; // TRUE for case compare
BYTE near MaxSymLen = 0; // longest symbol len
LSZ near lszFName; // Current input file
LSZ near OutputFileName = NULL; // output file name
FILE * near OutFile; // output file handle
BOOL near fOutputBroken = FALSE; // we have dirtied the database
VA near vaRootMod = vaNil; // module list
VA near vaCurMod = vaNil; // current module
VA near rgVaSym[MAXSYMPTRTBLSIZ]; // symbol list array
EXCLINK FAR * near pExcludeFileList = NULL; // exclude file list
struct mlist {
int erno;
char *text;
};
struct mlist WarnMsg[] = {
4500, "UNKNOWN WARNING\n\tContact Microsoft Product Support Services",
4501, "ignoring unknown option '%s'",
4502, "truncated .SBR file '%s' not in database",
};
struct mlist ErrorMsg[] = {
1500, "UNKNOWN ERROR\n\tContact Microsoft Product Support Services",
1501, "unknown character '%c' in option '%s'",
1502, "incomplete specification for option '%s'",
1503, "cannot write to file '%s'",
1504, "cannot position in file '%s'",
1505, "cannot read from file '%s'",
1506, "cannot open file '%s'",
1507, "cannot open temporary file '%s'",
1508, "cannot delete temporary file '%s'",
1509, "out of heap space",
1510, "corrupt .SBR file '%s'",
1511, "invalid response file specification",
1512, "database capacity exceeded",
1513, "nonincremental update requires all .SBR files",
1514, "all .SBR files truncated and not in database",
};
VOID
Error (int imsg, char *parg)
// print error number and message
//
{
printf ("mbrmake: error U%d : ",ErrorMsg[imsg].erno);
printf (ErrorMsg[imsg].text, parg);
printf ("\n");
Fatal();
}
VOID
Error2 (int imsg, char achar, char *parg)
// print error number and message with argument
//
{
printf ("mbrmake: error U%d : ",ErrorMsg[imsg].erno);
printf (ErrorMsg[imsg].text, achar, parg);
printf ("\n");
Fatal();
}
VOID
Warning (int imsg, char *parg)
// print warning number and message
//
{
printf ("mbrmake: warning U%d : ",WarnMsg[imsg].erno);
printf (WarnMsg[imsg].text, parg);
printf ("\n");
}
VOID
Fatal ()
// fatal error, attempt to shut down and exit
// if we already tried to shut down -- just abort without doing anything
{
static BOOL fTwice;
if (!fTwice) {
fTwice = TRUE;
if (fOutputBroken) {
if (OutFile) fclose(OutFile);
if (OutputFileName != NULL) unlink(OutputFileName);
}
CloseVM();
}
exit(4);
}
VOID
sigint ()
{
// signal(SIGBREAK, sigint);
// signal(SIGINT, sigint);
Fatal ();
}
LSZ
LszDup(LSZ lsz)
// like strdup only using LpvAllocCb to get the memory
//
{
LSZ lszDup;
lszDup = LpvAllocCb(strlen(lsz)+1);
strcpy(lszDup, lsz);
return lszDup;
}
LSZ
LszDupNewExt(LSZ pname, LSZ pext)
// duplicate the given filename changing the extension to be the given
//
{
int i, len, elen;
LSZ lsz;
len = strlen(pname);
elen = strlen(pext);
// I know this looks like I should be doing a runtime call but nothing
// does quite what I want here and I know that C6 will make great
// code for this loop [rm]
// find the first '.' starting from the back
for (i=len; --i >= 0; )
if (pname[i] == '.')
break;
// check to make sure we've got a real base name and not just all extension
//
if (i > 0) {
// replace the extension with what's in pext
lsz = LpvAllocCb(i + 1 + elen + 1); // base + dot + ext + nul
memcpy(lsz, pname, i+1);
strcpy(lsz+i+1, pext);
}
else {
// just stick the extension on the end...
lsz = LpvAllocCb(len + 1 + elen + 1); // fullname + dot + ext + nul
strcpy(lsz, pname);
strcat(lsz, ".");
strcat(lsz, pext);
}
return lsz;
}
VOID
AddExcludeFileList(LSZ pname)
// add the specifed filename to the exclusion list
//
{
EXCLINK FAR *pexc;
pexc = (EXCLINK FAR *)LpvAllocCb(sizeof(EXCLINK));
pexc->pxfname = LszDup(ToAbsPath(pname, c_cwd));
if (pExcludeFileList == NULL)
pexc->xnext = NULL;
else
pexc->xnext = pExcludeFileList;
pExcludeFileList = pexc;
}
BOOL
FValidHeader()
// Read in the header of a .sbr file -- return TRUE if it is valid
//
{
// test if this is a truncated (i.e. already installed) .sbr file
//
if (GetSBRRec() == S_EOF)
return FALSE;
if (r_rectyp != SBR_REC_HEADER)
SBRCorrupt("header not correct record type");
if (r_lang == SBR_L_C)
fCase = TRUE;
if (r_majv != 1 || r_minv != 1)
SBRCorrupt("incompatible .sbr format\n");
#ifdef DEBUG
if (OptD & 1) DecodeSBR();
#endif
return TRUE;
}
#ifdef PROFILE
// profile prototypes and typedefs
#include "casts.h"
#include "profile.h"
#endif
VOID __cdecl
main (argc, argv)
int argc;
char *argv[];
{
int i;
char *parg;
long lArgPosn;
#ifdef PROFILE
PROFINIT(PT_USER|PT_USEKP, (FPC)NULL);
PROFCLEAR(PT_USER);
PROFON(PT_USER);
#endif
// signal(SIGBREAK, sigint);
// signal(SIGINT, sigint);
printf("Microsoft (R) mbrmake Utility ");
printf(VERS(rmj, rmm, rup));
printf(CPYRIGHT);
if (argc == 1) Usage();
getcwd(c_cwd, sizeof(c_cwd));
ToBackSlashes(c_cwd);
parg = ParseArgs(argc, argv);
if (!parg)
Usage();
InitVM();
for (i=0; i < MAXSYMPTRTBLSIZ; i++) // init symbol lists
rgVaSym[i] = vaNil;
lArgPosn = GetArgPosn();
do {
ToBackSlashes(parg);
if (forfile(parg, A_ALL, MarkNewSBR, NULL) == 0)
Error(ERR_OPEN_FAILED, parg);
}
while (parg = NextArg());
if (!OptN && FOpenBSC(OutputFileName)) {
InstallBSC();
CloseBSC();
}
else
NumberSBR();
SetArgPosn(lArgPosn);
parg = NextArg();
do {
if (forfile(parg, A_ALL, ProcessSBR, NULL) == 0)
Error(ERR_OPEN_FAILED, parg);
}
while (parg = NextArg());
// this sort must happen before all the other calls below as they
// use the sorted version of the list and not the raw symbols
SortAtoms(); // create a sorted version of the atoms
#ifdef DEBUG
if (OptD & 128) DebugDump();
#endif
CleanUp (); // General cleaning
#ifdef DEBUG
if (OptD & 16) DebugDump();
#endif
WriteBSC (OutputFileName); // write .bsc Source Data Base
#ifdef PROFILE
PROFOFF(PT_USER);
PROFDUMP(PT_USER, (FPC)"mbrmake.pro");
PROFFREE(PT_USER);
#endif
if (!OptN) {
// truncate the .sbr files now
SetArgPosn(lArgPosn);
parg = NextArg();
do {
if (forfile(parg, A_ALL, TruncateSBR, NULL) == 0)
Error(ERR_OPEN_FAILED, parg);
}
while (parg = NextArg());
// touch the .bsc file so it has a date later than all the .sbrs
{
FILE *fh;
int buf = 0;
if (!(fh = fopen(OutputFileName, "ab"))) {
Error(ERR_OPEN_FAILED, OutputFileName);
}
if (fwrite(&buf, 1, 1, fh)==0) {
Error(ERR_WRITE_FAILED, OutputFileName);
}
fclose(fh);
}
}
CloseVM();
exit (0);
}
static VOID
ProcessSBR(char *lszName)
// process one .sbr file with the given name
//
{
lszFName = LszDup(lszName);
if ((fhCur = open(lszFName, O_BINARY|O_RDONLY)) == -1) {
Error(ERR_OPEN_FAILED, lszFName);
}
isbrCur = gSBR(VaSbrFrName(lszFName)).isbr;
if (OptV)
printf("Processing: %s ..\n", lszFName);
if (!FValidHeader()) {
FreeLpv (lszFName);
close(fhCur);
return;
}
// Add .SBR data to lists
InstallSBR ();
FreeOrdList (); // free ordinal aliases
close(fhCur);
FreeLpv (lszFName);
}
static VOID
TruncateSBR(char *lszName)
// once the .sbr file is used -- truncate it
//
{
int fh;
if (unlink(lszName) == -1) {
Error(ERR_OPEN_FAILED, lszFName);
}
if ((fh = open(lszName, O_CREAT|O_BINARY, S_IREAD|S_IWRITE)) == -1) {
Error(ERR_OPEN_FAILED, lszFName);
}
close(fh);
}
VOID
Usage()
{
#ifdef DEBUG
printf("usage: mbrmake [-Emu] [-Ei ...] [-vd] [-help] [-o <.BSC>] [@<file>] <.sbr>...\n\n");
#else
printf("usage: mbrmake [-Emu] [-Ei ...] [-v] [-help] [-o <.BSC>] [@<file>] <.sbr>...\n\n");
#endif
printf(" @<file> Get arguments from specified file\n");
printf(" /E... Exclude:\n");
printf(" s system files\n");
printf(" i <file> named include file <file>\n");
printf(" i ( <files> ) named include file list <files>\n");
printf(" m macro expanded symbols\n");
printf(" /I... Include:\n");
printf(" u unreferenced symbols\n");
printf(" /o <file> output source database name\n");
printf(" /n no incremental (full builds, .sbr's preserved)\n");
printf(" /v verbose output\n");
printf(" /help Quick Help\n");
#ifdef DEBUG
printf(" /d show debugging information\n");
printf(" 1 sbrdump .sbr files as they come in\n");
printf(" 2 show every duplicate MbrAddAtom\n");
printf(" 4 emit warning on forward referenced ordinal\n");
printf(" 8 show prop data as new items are added\n");
printf(" 16 bscdump database after cleanup\n");
printf(" 32 emit information about what cleanup is doing\n");
printf(" 64 emit list of sorted modules after sorting\n");
printf(" 128 bscdump database before cleanup\n");
printf(" 256 give info about duplicate/excluded modules\n");
#endif
exit(1);
}
FILE *fileResp;
int cargs;
char ** vargs;
int iarg = 1;
long lFilePosnLast;
LONG
GetArgPosn()
// save the current position on the command line
//
{
if (fileResp)
return lFilePosnLast;
else
return (LONG)iarg - 1;
}
VOID
SetArgPosn(LONG lArgPosn)
// restore the command line parsing position
//
{
if (fileResp) {
fseek(fileResp, lArgPosn, SEEK_SET);
iarg = 0;
}
else
iarg = (int)lArgPosn;
}
char *
NextArg()
// get the next argument from the response file or the command line
//
{
static char buf[PATH_BUF];
char *pch;
int c;
BOOL fQuote = FALSE;
if (iarg >= cargs)
return NULL;
if (fileResp) {
pch = buf;
lFilePosnLast = ftell(fileResp);
for (;;) {
c = getc(fileResp);
switch (c) {
case '"':
if (fQuote) {
*pch = '\0';
return buf;
}
else {
fQuote = TRUE;
continue;
}
case EOF:
iarg = cargs;
if (pch == buf)
return NULL;
*pch = '\0';
return buf;
case ' ':
case '\t':
case '\r':
case '\f':
case '\n':
if (fQuote)
goto quoted;
if (pch == buf)
continue;
*pch = '\0';
return buf;
default:
quoted:
if (pch < buf + sizeof(buf) - 1)
*pch++ = (char)c;
break;
}
}
}
else
return vargs[iarg++];
}
char *
ParseArgs(int argc, char **argv)
// parse the command line or response file
//
{
char *respName;
char *pchWord;
int len;
cargs = argc;
vargs = argv;
for (;;) {
pchWord = NextArg();
if (pchWord == NULL)
return pchWord;
if (pchWord[0] == '@') {
if (fileResp)
Error(ERR_BAD_RESPONSE, "");
else if (pchWord[1])
respName = pchWord+1;
else if (!(respName = NextArg()))
Error(ERR_BAD_RESPONSE, "");
fileResp = fopen(respName, "r");
if (!fileResp)
Error(ERR_OPEN_FAILED, respName);
cargs++;
continue;
}
if (pchWord[0] != '-' && pchWord[0] != '/')
return pchWord;
switch (pchWord[1]) {
case 'n':
OptN = TRUE;
break;
case 'o':
if (pchWord[2])
pchWord += 2;
else if (!(pchWord = NextArg()))
Usage();
OutputFileName = LszDupNewExt (pchWord, "bsc");
break;
#ifdef DEBUG
case 'd':
OptD = 1;
if (pchWord[2]) OptD = atoi(pchWord+2);
break;
#endif
case 'E':
switch (pchWord[2]) {
case 0:
Error (ERR_MISSING_OPTION, pchWord);
break;
case 'm':
OptEm = TRUE;
break;
case 's':
OptEs = TRUE;
break;
default:
Error2 (ERR_UNKNOWN_OPTION, pchWord[2], pchWord);
break;
case 'i':
if (pchWord[3])
pchWord += 3;
else
pchWord = NextArg();
if (!pchWord)
Error (ERR_MISSING_OPTION, "-Ei");
if (pchWord[0] != '(') {
AddExcludeFileList(pchWord);
break;
}
if (pchWord[1])
pchWord++;
else
pchWord = NextArg();
for ( ;pchWord != NULL; pchWord = NextArg()) {
len = strlen(pchWord);
if (pchWord[len-1] != ')') {
AddExcludeFileList(pchWord);
}
else if (len > 1) {
pchWord[len-1] = 0;
AddExcludeFileList(pchWord);
break;
}
else
break;
}
if (pchWord == NULL)
Error (ERR_MISSING_OPTION, "-Ei (...");
}
break;
case 'I':
switch (pchWord[2]) {
case 'u':
OptIu = TRUE;
break;
default:
Error2 (ERR_UNKNOWN_OPTION, pchWord[2], pchWord);
break;
}
break;
case 'H':
case 'h':
if ((strcmpi (pchWord+1, "help")) == 0) {
if (spawnlp (P_WAIT, "qh", "-u", "mbrmake.exe", NULL))
Usage();
exit (0);
}
break;
case 'v':
OptV = TRUE;
break;
default:
Warning (WARN_OPTION_IGNORED, pchWord);
break;
}
}
}
static VOID
MarkNewSBR(char *lszName)
// mark the specified SBR file as requiring update
//
{
int fh;
char ch;
if (!OutputFileName)
OutputFileName = LszDupNewExt (lszName, "bsc");
if ((fh = open(lszName, O_BINARY|O_RDONLY)) == -1) {
Error(ERR_OPEN_FAILED, lszFName);
}
// if the file has non zero length then it is being updated -- else
// it is just a stub that will not affect the database this time around
//
if (read(fh, &ch, 1) != 1)
VaSbrAdd(SBR_NEW, lszName); // to remain in .bsc
else
VaSbrAdd(SBR_NEW|SBR_UPDATE, lszName); // to be re-installed in .bsc
close (fh);
}