816 lines
24 KiB
C
816 lines
24 KiB
C
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Microsoft Windows
|
||
|
// Copyright (C) Microsoft Corporation, 1989 - 1994
|
||
|
//
|
||
|
// File: buildscn.c
|
||
|
//
|
||
|
// Contents: Directory and File scanning functions for Build.exe
|
||
|
//
|
||
|
//
|
||
|
// History: 16-May-89 SteveWo Created
|
||
|
// ... see SLM logs
|
||
|
// 26-Jul-94 LyleC Cleanup/Add pass0 support
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#include "build.h"
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: AddShowDir
|
||
|
//
|
||
|
// Synopsis: Add a directory to the ShowDir array
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
VOID
|
||
|
AddShowDir(DIRREC *pdr)
|
||
|
{
|
||
|
AssertDir(pdr);
|
||
|
if (CountShowDirs >= MAX_BUILD_DIRECTORIES) {
|
||
|
static BOOL fError = FALSE;
|
||
|
|
||
|
if (!fError) {
|
||
|
BuildError(
|
||
|
"Show Directory table overflow, using first %u entries\n",
|
||
|
MAX_BUILD_DIRECTORIES);
|
||
|
fError = TRUE;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
ShowDirs[CountShowDirs++] = pdr;
|
||
|
}
|
||
|
pdr->DirFlags |= DIRDB_SHOWN;
|
||
|
}
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: AddIncludeDir
|
||
|
//
|
||
|
// Synopsis: Add a directory to the IncludeDirs array
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
VOID
|
||
|
AddIncludeDir(DIRREC *pdr, UINT *pui)
|
||
|
{
|
||
|
AssertDir(pdr);
|
||
|
assert(pdr->FindCount >= 1);
|
||
|
assert(*pui <= MAX_INCLUDE_DIRECTORIES);
|
||
|
if (*pui >= MAX_INCLUDE_DIRECTORIES) {
|
||
|
BuildError(
|
||
|
"Include Directory table overflow, %u entries allowed\n",
|
||
|
MAX_INCLUDE_DIRECTORIES);
|
||
|
exit(16);
|
||
|
}
|
||
|
IncludeDirs[(*pui)++] = pdr;
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: ScanGlobalIncludeDirectory
|
||
|
//
|
||
|
// Synopsis: Scans a global include directory and adds it to the
|
||
|
// IncludeDir array.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
VOID
|
||
|
ScanGlobalIncludeDirectory(LPSTR path)
|
||
|
{
|
||
|
DIRREC *pdr;
|
||
|
|
||
|
if ((pdr = ScanDirectory(path)) != NULL) {
|
||
|
AddIncludeDir(pdr, &CountIncludeDirs);
|
||
|
pdr->DirFlags |= DIRDB_GLOBAL_INCLUDES;
|
||
|
if (fShowTreeIncludes && !(pdr->DirFlags & DIRDB_SHOWN)) {
|
||
|
AddShowDir(pdr);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: ScanIncludeEnv
|
||
|
//
|
||
|
// Synopsis: Scans all include directories specified in the INCLUDE
|
||
|
// environment variable.
|
||
|
//
|
||
|
// Arguments: [IncludeEnv] -- value of the INCLUDE environment variable.
|
||
|
//
|
||
|
// Notes: The INCLUDE variable is a string with a list of directories
|
||
|
// separated by semicolons (;).
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
VOID
|
||
|
ScanIncludeEnv(
|
||
|
LPSTR IncludeEnv
|
||
|
)
|
||
|
{
|
||
|
char path[DB_MAX_PATH_LENGTH] = {0};
|
||
|
LPSTR IncDir, IncDirEnd;
|
||
|
UINT cb;
|
||
|
|
||
|
if (!IncludeEnv) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (DEBUG_1) {
|
||
|
BuildMsgRaw("ScanIncludeEnv(%s)\n", IncludeEnv);
|
||
|
}
|
||
|
|
||
|
IncDir = IncludeEnv;
|
||
|
while (*IncDir) {
|
||
|
IncDir++;
|
||
|
}
|
||
|
|
||
|
while (IncDir > IncludeEnv) {
|
||
|
IncDirEnd = IncDir;
|
||
|
while (IncDir > IncludeEnv) {
|
||
|
if (*--IncDir == ';') {
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (*IncDir == ';') {
|
||
|
if (cb = (UINT)(IncDirEnd-IncDir-1)) {
|
||
|
strncpy( path, IncDir+1, cb );
|
||
|
}
|
||
|
} else {
|
||
|
if (cb = (UINT)(IncDirEnd-IncDir)) {
|
||
|
strncpy( path, IncDir, cb );
|
||
|
}
|
||
|
}
|
||
|
if (cb) {
|
||
|
path[ cb ] = '\0';
|
||
|
while (path[ 0 ] == ' ') {
|
||
|
strcpy( path, &path[ 1 ] );
|
||
|
cb--;
|
||
|
}
|
||
|
|
||
|
while (cb && path[--cb] == ' ') {
|
||
|
path[ cb ] = '\0';
|
||
|
}
|
||
|
if (path[0]) {
|
||
|
ScanGlobalIncludeDirectory(path);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: ScanSubDir
|
||
|
//
|
||
|
// Synopsis: Scans all the files in the given directory, sets the
|
||
|
// directory flags appropriately (e.g. DIRDB_SOURCES, etc),
|
||
|
// and adds a list of interesting files to the Files list in
|
||
|
// the DirDB structure for the directory.
|
||
|
//
|
||
|
// Arguments: [pszDir] -- Name of directory to scan
|
||
|
// [pdr] -- [out] Filled in DIRREC on return
|
||
|
//
|
||
|
// Notes: An 'interesting' file is one which has a recognized
|
||
|
// extension. See the InsertFileDB and MatchFileDesc
|
||
|
// functions for more info.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
VOID
|
||
|
ScanSubDir(LPSTR pszDir, DIRREC *pdr)
|
||
|
{
|
||
|
char FileName[DB_MAX_PATH_LENGTH];
|
||
|
FILEREC *FileDB, **FileDBNext;
|
||
|
WIN32_FIND_DATA FindFileData;
|
||
|
HDIR FindHandle;
|
||
|
ULONG DateTime;
|
||
|
USHORT Attr;
|
||
|
|
||
|
strcat(pszDir, "\\");
|
||
|
strcat(pszDir, "*.*");
|
||
|
|
||
|
pdr->DirFlags |= DIRDB_SCANNED;
|
||
|
FindHandle = FindFirstFile(pszDir, &FindFileData);
|
||
|
if (FindHandle == (HDIR)INVALID_HANDLE_VALUE) {
|
||
|
if (DEBUG_1) {
|
||
|
BuildMsg("FindFirstFile(%s) failed.\n", pszDir);
|
||
|
}
|
||
|
return;
|
||
|
}
|
||
|
do {
|
||
|
Attr = (USHORT)(FindFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
|
||
|
if ((Attr & FILE_ATTRIBUTE_DIRECTORY) &&
|
||
|
(!strcmp(FindFileData.cFileName, ".") ||
|
||
|
!strcmp(FindFileData.cFileName, ".."))) {
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
CopyString(FileName, FindFileData.cFileName, TRUE);
|
||
|
|
||
|
FileTimeToDosDateTime(&FindFileData.ftLastWriteTime,
|
||
|
((LPWORD) &DateTime) + 1,
|
||
|
(LPWORD) &DateTime);
|
||
|
|
||
|
if ((pdr->DirFlags & DIRDB_NEW) == 0 &&
|
||
|
(FileDB = LookupFileDB(pdr, FileName)) != NULL) {
|
||
|
|
||
|
if (FileDB->FileFlags & FILEDB_PASS0)
|
||
|
pdr->DirFlags |= DIRDB_PASS0;
|
||
|
|
||
|
//
|
||
|
// Clear the file missing flag, since we know the file exists now.
|
||
|
// This flag may be set if the file was generated during pass zero.
|
||
|
//
|
||
|
if (FileDB->FileFlags & FILEDB_FILE_MISSING)
|
||
|
FileDB->FileFlags &= ~FILEDB_FILE_MISSING;
|
||
|
|
||
|
//
|
||
|
// The time we last stored for this file is different than the
|
||
|
// actual time on the file, so force it to be rescanned.
|
||
|
//
|
||
|
if (FileDB->DateTime != DateTime) {
|
||
|
if (FileDB->FileFlags & (FILEDB_SOURCE | FILEDB_HEADER)) {
|
||
|
FileDB->FileFlags &= ~FILEDB_SCANNED;
|
||
|
}
|
||
|
else {
|
||
|
FileDB->FileFlags |= FILEDB_SCANNED;
|
||
|
}
|
||
|
|
||
|
if (DEBUG_1) {
|
||
|
BuildMsg(
|
||
|
"%s - DateTime (%lx != %lx)\n",
|
||
|
FileDB->Name,
|
||
|
FileDB->DateTime,
|
||
|
DateTime);
|
||
|
}
|
||
|
|
||
|
FileDB->DateTime = DateTime;
|
||
|
FileDB->Attr = Attr;
|
||
|
}
|
||
|
else {
|
||
|
FileDB->FileFlags |= FILEDB_SCANNED;
|
||
|
}
|
||
|
}
|
||
|
else {
|
||
|
FileDB = InsertFileDB(pdr, FileName, DateTime, Attr, 0);
|
||
|
}
|
||
|
} while (FindNextFile(FindHandle, &FindFileData));
|
||
|
|
||
|
FindClose(FindHandle);
|
||
|
|
||
|
if ((pdr->DirFlags & DIRDB_DIRS) && (pdr->DirFlags & DIRDB_SOURCES))
|
||
|
{
|
||
|
BuildError("%s\\sources. unexpected in directory with DIRS file\n",
|
||
|
pdr->Name);
|
||
|
BuildError("Ignoring %s\\sources.\n", pdr->Name);
|
||
|
|
||
|
pdr->DirFlags &= ~DIRDB_SOURCES;
|
||
|
}
|
||
|
//
|
||
|
// Scan each file in this directory unless using QuickZero
|
||
|
//
|
||
|
if (fQuickZero && fFirstScan)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
FileDBNext = &pdr->Files;
|
||
|
while (FileDB = *FileDBNext) {
|
||
|
if (!(FileDB->FileFlags & (FILEDB_DIR | FILEDB_SCANNED))) {
|
||
|
if (ScanFile(FileDB)) {
|
||
|
AllDirsModified = TRUE;
|
||
|
}
|
||
|
}
|
||
|
FileDBNext = &FileDB->Next;
|
||
|
}
|
||
|
DeleteUnscannedFiles(pdr);
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: ScanDirectory
|
||
|
//
|
||
|
// Synopsis: Tries to find the given directory in the database, and if
|
||
|
// not found calls ScanSubDir.
|
||
|
//
|
||
|
// Arguments: [pszDir] -- Directory to scan
|
||
|
//
|
||
|
// Returns: Filled in DIRREC structure for the directory.
|
||
|
//
|
||
|
// Notes: If fQuicky (-z or -Z options) are set, then instead of calling
|
||
|
// ScanSubDir, which is long, it just checks for known files, like
|
||
|
// 'sources' for 'makefile' to determine whether or not the
|
||
|
// directory should be compiled.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
PDIRREC
|
||
|
ScanDirectory(LPSTR pszDir)
|
||
|
{
|
||
|
DIRREC *pdr;
|
||
|
char FullPath[DB_MAX_PATH_LENGTH];
|
||
|
|
||
|
if (DEBUG_1) {
|
||
|
BuildMsgRaw("ScanDirectory(%s)\n", pszDir);
|
||
|
}
|
||
|
|
||
|
if (!CanonicalizePathName(pszDir, CANONICALIZE_DIR, FullPath)) {
|
||
|
if (DEBUG_1) {
|
||
|
BuildMsgRaw("CanonicalizePathName failed\n");
|
||
|
}
|
||
|
return(NULL);
|
||
|
}
|
||
|
pszDir = FullPath;
|
||
|
|
||
|
if ((pdr = LoadDirDB(pszDir)) == NULL) {
|
||
|
return(NULL);
|
||
|
}
|
||
|
|
||
|
if (fQuicky && (!fQuickZero)) {
|
||
|
|
||
|
if (!(pdr->DirFlags & DIRDB_SCANNED)) {
|
||
|
pdr->DirFlags |= DIRDB_SCANNED;
|
||
|
if (ProbeFile(pdr->Name, "sources") != -1) {
|
||
|
pdr->DirFlags |= DIRDB_SOURCES | DIRDB_MAKEFILE;
|
||
|
}
|
||
|
else
|
||
|
if (ProbeFile(pdr->Name, "mydirs") != -1 ||
|
||
|
ProbeFile(pdr->Name, "dirs") != -1 ||
|
||
|
ProbeFile(pdr->Name, pszTargetDirs) != -1) {
|
||
|
|
||
|
pdr->DirFlags |= DIRDB_DIRS;
|
||
|
if (ProbeFile(pdr->Name, "makefil0") != -1) {
|
||
|
pdr->DirFlags |= DIRDB_MAKEFIL0;
|
||
|
}
|
||
|
if (ProbeFile(pdr->Name, "makefil1") != -1) {
|
||
|
pdr->DirFlags |= DIRDB_MAKEFIL1;
|
||
|
}
|
||
|
if (ProbeFile(pdr->Name, "makefile") != -1) {
|
||
|
pdr->DirFlags |= DIRDB_MAKEFILE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return(pdr);
|
||
|
}
|
||
|
|
||
|
if (pdr->DirFlags & DIRDB_SCANNED) {
|
||
|
return(pdr);
|
||
|
}
|
||
|
|
||
|
if (!RecurseLevel && fNoisyScan) {
|
||
|
ClearLine();
|
||
|
BuildMsgRaw(" Scanning %s ", pszDir);
|
||
|
if (fDebug || !(BOOL) _isatty(_fileno(stderr))) {
|
||
|
BuildMsgRaw(szNewLine);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ScanSubDir(pszDir, pdr);
|
||
|
|
||
|
if (!RecurseLevel) {
|
||
|
ClearLine();
|
||
|
}
|
||
|
return(pdr);
|
||
|
}
|
||
|
|
||
|
|
||
|
#define BUILD_TLIB_INCLUDE_STMT "importlib"
|
||
|
#define BUILD_TLIB_INCLUDE_STMT_LENGTH (sizeof( BUILD_TLIB_INCLUDE_STMT )-1)
|
||
|
|
||
|
#define BUILD_MIDL_INCLUDE_STMT "import"
|
||
|
#define BUILD_MIDL_INCLUDE_STMT_LENGTH (sizeof( BUILD_MIDL_INCLUDE_STMT )-1)
|
||
|
|
||
|
#define BUILD_RC_INCLUDE_STMT "rcinclude"
|
||
|
#define BUILD_RC_INCLUDE_STMT_LENGTH (sizeof( BUILD_RC_INCLUDE_STMT )-1)
|
||
|
|
||
|
#define BUILD_ASN_INCLUDE_STMT "--<"
|
||
|
#define BUILD_ASN_INCLUDE_STMT_LENGTH (sizeof( BUILD_ASN_INCLUDE_STMT )-1)
|
||
|
|
||
|
#define BUILD_INCLUDE_STMT "include"
|
||
|
#define BUILD_INCLUDE_STMT_LENGTH (sizeof( BUILD_INCLUDE_STMT )-1)
|
||
|
|
||
|
#define BUILD_VER_COMMENT "/*++ BUILD Version: "
|
||
|
#define BUILD_VER_COMMENT_LENGTH (sizeof( BUILD_VER_COMMENT )-1)
|
||
|
|
||
|
#define BUILD_MASM_VER_COMMENT ";;;; BUILD Version: "
|
||
|
#define BUILD_MASM_VER_COMMENT_LENGTH (sizeof( BUILD_MASM_VER_COMMENT )-1)
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: IsIncludeStatement
|
||
|
//
|
||
|
// Synopsis: Tries to determine whether or not a given line contains an
|
||
|
// include statement (e.g. #include <foobar.h> ).
|
||
|
//
|
||
|
// Arguments: [pfr] -- FILEREC of file being scanned
|
||
|
// [p] -- Current line of file
|
||
|
//
|
||
|
// Returns: NULL if line is not an include statment. Returns pointer to
|
||
|
// beginning of filename if it is (e.g. <foobar.h> ).
|
||
|
//
|
||
|
// Notes: The returned filename includes the surrounding quotes or
|
||
|
// brackets, if any. Also, the pointer is just a pointer into
|
||
|
// the given string, not a separate copy.
|
||
|
//
|
||
|
// Supported statements are:
|
||
|
// All file types: #include <filename> and #include "filename"
|
||
|
// MIDL files: import "filename"
|
||
|
// RC files: rcinclude filename
|
||
|
// MKTYPLIB files: importlib("filename")
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#define IsTokenPrefix0(psz, szToken, cchToken) \
|
||
|
(strncmp((psz), (szToken), (cchToken)) == 0)
|
||
|
|
||
|
#define IsTokenPrefix(psz, szToken, cchToken) \
|
||
|
(IsTokenPrefix0((psz), (szToken), (cchToken)) && \
|
||
|
(psz)[cchToken] != '\0')
|
||
|
|
||
|
#define IsTokenMatch(psz, szToken, cchToken) \
|
||
|
(IsTokenPrefix((psz), (szToken), (cchToken)) && \
|
||
|
!iscsym((psz)[cchToken]))
|
||
|
|
||
|
#define IsCiTokenPrefix0(psz, szToken, cchToken) \
|
||
|
(_strnicmp((psz), (szToken), (cchToken)) == 0)
|
||
|
|
||
|
#define IsCiTokenPrefix(psz, szToken, cchToken) \
|
||
|
(IsCiTokenPrefix0((psz), (szToken), (cchToken)) && \
|
||
|
(psz)[cchToken] != '\0')
|
||
|
|
||
|
#define IsCiTokenMatch(psz, szToken, cchToken) \
|
||
|
(IsCiTokenPrefix((psz), (szToken), (cchToken)) && \
|
||
|
!iscsym((psz)[cchToken]))
|
||
|
|
||
|
LPSTR
|
||
|
IsIncludeStatement(FILEREC *pfr, LPSTR p)
|
||
|
{
|
||
|
if (!p || *p == '\0')
|
||
|
return NULL;
|
||
|
|
||
|
if (!(pfr->FileFlags & (FILEDB_MASM | FILEDB_MIDL | FILEDB_MKTYPLIB | FILEDB_RC | FILEDB_ASN))) {
|
||
|
if (*p != '#') {
|
||
|
return(NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (*p == '#')
|
||
|
p++;
|
||
|
|
||
|
while (isspace(*p)) {
|
||
|
p++;
|
||
|
}
|
||
|
|
||
|
if (IsTokenMatch(p, BUILD_INCLUDE_STMT, BUILD_INCLUDE_STMT_LENGTH)) {
|
||
|
p += BUILD_INCLUDE_STMT_LENGTH;
|
||
|
}
|
||
|
else
|
||
|
if ((pfr->FileFlags & FILEDB_MASM) &&
|
||
|
IsCiTokenMatch(p, BUILD_INCLUDE_STMT, BUILD_INCLUDE_STMT_LENGTH)) {
|
||
|
p += BUILD_INCLUDE_STMT_LENGTH;
|
||
|
}
|
||
|
else
|
||
|
if ((pfr->FileFlags & FILEDB_MIDL) &&
|
||
|
IsTokenMatch(p, BUILD_MIDL_INCLUDE_STMT, BUILD_MIDL_INCLUDE_STMT_LENGTH)) {
|
||
|
p += BUILD_MIDL_INCLUDE_STMT_LENGTH;
|
||
|
}
|
||
|
else
|
||
|
if ((pfr->FileFlags & FILEDB_RC) &&
|
||
|
IsTokenMatch(p, BUILD_RC_INCLUDE_STMT, BUILD_RC_INCLUDE_STMT_LENGTH)) {
|
||
|
|
||
|
p += BUILD_RC_INCLUDE_STMT_LENGTH;
|
||
|
}
|
||
|
else
|
||
|
if ((pfr->FileFlags & FILEDB_ASN) &&
|
||
|
IsTokenPrefix0(p, BUILD_ASN_INCLUDE_STMT, BUILD_ASN_INCLUDE_STMT_LENGTH)) {
|
||
|
|
||
|
p += BUILD_ASN_INCLUDE_STMT_LENGTH;
|
||
|
}
|
||
|
else
|
||
|
if ((pfr->FileFlags & FILEDB_MKTYPLIB) &&
|
||
|
IsTokenMatch(p, BUILD_TLIB_INCLUDE_STMT, BUILD_TLIB_INCLUDE_STMT_LENGTH)) {
|
||
|
p += BUILD_TLIB_INCLUDE_STMT_LENGTH;
|
||
|
while (isspace(*p)) {
|
||
|
p++;
|
||
|
}
|
||
|
|
||
|
if (*p == '(') // Skip the open paren and get to the quote.
|
||
|
p++;
|
||
|
}
|
||
|
else {
|
||
|
return(NULL);
|
||
|
}
|
||
|
|
||
|
while (isspace(*p)) {
|
||
|
p++;
|
||
|
}
|
||
|
return(p);
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: IsPragmaHdrStop
|
||
|
//
|
||
|
// Synopsis: Determines if the given line is a #pragma hdrstop line
|
||
|
//
|
||
|
// Arguments: [p] -- String to analyze
|
||
|
//
|
||
|
// Returns: TRUE if the line is a pragma hdrstop
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
BOOL
|
||
|
IsPragmaHdrStop(LPSTR p)
|
||
|
{
|
||
|
static char szPragma[] = "pragma";
|
||
|
static char szHdrStop[] = "hdrstop";
|
||
|
|
||
|
if (*p == '#') {
|
||
|
while (*++p == ' ') {
|
||
|
;
|
||
|
}
|
||
|
if (strncmp(p, szPragma, sizeof(szPragma) - 1) == 0 &&
|
||
|
*(p += sizeof(szPragma) - 1) == ' ') {
|
||
|
|
||
|
while (*p == ' ') {
|
||
|
p++;
|
||
|
}
|
||
|
if (strncmp(p, szHdrStop, sizeof(szHdrStop) - 1) == 0 &&
|
||
|
!iscsym(p[sizeof(szHdrStop) - 1])) {
|
||
|
|
||
|
return(TRUE);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
|
||
|
//+---------------------------------------------------------------------------
|
||
|
//
|
||
|
// Function: ScanFile
|
||
|
//
|
||
|
// Synopsis: Scans the given file to determine files which it includes.
|
||
|
//
|
||
|
// Arguments: [FileDB] -- File to scan.
|
||
|
//
|
||
|
// Returns: TRUE if successful
|
||
|
//
|
||
|
// Notes: This function is a nop if the given file does not have either
|
||
|
// the FILEDB_SOURCE or FILEDB_HEADER flag set.
|
||
|
// (see InsertSourceDB)
|
||
|
//
|
||
|
// Note that the performance of this function is critical since
|
||
|
// it is called for every file in each directory.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#define ASN_NONE 0 // not in Asn INCLUDES statement
|
||
|
#define ASN_START 1 // expectimg "INCLUDES" token
|
||
|
#define ASN_FILENAME 2 // expecting a quoted "filename"
|
||
|
#define ASN_COMMA 3 // expecting end token (">--") or comma
|
||
|
|
||
|
#define ASN_CONTINUATION 8 // expecting comment token first
|
||
|
|
||
|
char *
|
||
|
AsnStateToString(UINT AsnState)
|
||
|
{
|
||
|
static char buf[100];
|
||
|
char *psz;
|
||
|
|
||
|
switch (AsnState & ~ASN_CONTINUATION) {
|
||
|
case ASN_NONE: psz = "None"; break;
|
||
|
case ASN_START: psz = "Start"; break;
|
||
|
case ASN_FILENAME: psz = "Filename"; break;
|
||
|
case ASN_COMMA: psz = "Comma"; break;
|
||
|
default: psz = "???"; break;
|
||
|
}
|
||
|
sprintf(buf, "%s%s", psz, (AsnState & ASN_CONTINUATION)? "+Cont" : "");
|
||
|
return(buf);
|
||
|
}
|
||
|
|
||
|
|
||
|
BOOL
|
||
|
ScanFile(
|
||
|
PFILEREC FileDB
|
||
|
)
|
||
|
{
|
||
|
FILE *FileHandle;
|
||
|
char CloseQuote;
|
||
|
LPSTR p;
|
||
|
LPSTR IncludeFileName, TextLine;
|
||
|
BOOL fFirst = TRUE;
|
||
|
USHORT IncFlags = 0;
|
||
|
UINT i, cline;
|
||
|
UINT AsnState = ASN_NONE;
|
||
|
|
||
|
if ((FileDB->FileFlags & (FILEDB_SOURCE | FILEDB_HEADER)) == 0) {
|
||
|
FileDB->FileFlags |= FILEDB_SCANNED;
|
||
|
return(TRUE);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Don't scan non-pass-zero files if we're doing pass zero.
|
||
|
//
|
||
|
if (fPassZero && (FileDB->FileFlags & FILEDB_PASS0) == 0)
|
||
|
return TRUE;
|
||
|
|
||
|
if (!SetupReadFile(
|
||
|
FileDB->Dir->Name,
|
||
|
FileDB->Name,
|
||
|
FileDB->pszCommentToEOL,
|
||
|
&FileHandle)) {
|
||
|
return(FALSE);
|
||
|
}
|
||
|
|
||
|
if (!RecurseLevel && fNoisyScan) {
|
||
|
ClearLine();
|
||
|
BuildMsgRaw(
|
||
|
" Scanning %s ",
|
||
|
FormatPathName(FileDB->Dir->Name, FileDB->Name));
|
||
|
if (!(BOOL) _isatty(_fileno(stderr))) {
|
||
|
BuildMsgRaw(szNewLine);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
FileDB->SourceLines = 0;
|
||
|
FileDB->Version = 0;
|
||
|
|
||
|
MarkIncludeFileRecords( FileDB );
|
||
|
FileDB->FileFlags |= FILEDB_SCANNED;
|
||
|
|
||
|
AllDirsModified = TRUE;
|
||
|
|
||
|
while ((TextLine = ReadLine(FileHandle)) != NULL) {
|
||
|
if (fFirst) {
|
||
|
fFirst = FALSE;
|
||
|
if (FileDB->FileFlags & FILEDB_HEADER) {
|
||
|
if (FileDB->FileFlags & FILEDB_MASM) {
|
||
|
if (!strncmp( TextLine,
|
||
|
BUILD_MASM_VER_COMMENT,
|
||
|
BUILD_MASM_VER_COMMENT_LENGTH)) {
|
||
|
FileDB->Version = (USHORT)
|
||
|
atoi( TextLine + BUILD_MASM_VER_COMMENT_LENGTH);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
if (!strncmp( TextLine,
|
||
|
BUILD_VER_COMMENT,
|
||
|
BUILD_VER_COMMENT_LENGTH)) {
|
||
|
FileDB->Version = (USHORT)
|
||
|
atoi( TextLine + BUILD_VER_COMMENT_LENGTH);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (AsnState != ASN_NONE) {
|
||
|
p = TextLine;
|
||
|
}
|
||
|
else {
|
||
|
p = IsIncludeStatement(FileDB, TextLine);
|
||
|
}
|
||
|
|
||
|
if (p != NULL) {
|
||
|
USHORT IncFlagsNew = IncFlags;
|
||
|
|
||
|
if (FileDB->FileFlags & FILEDB_ASN) {
|
||
|
if (AsnState & ASN_CONTINUATION) {
|
||
|
if (p[0] != '-' || p[1] != '-') {
|
||
|
AsnState = ASN_NONE; // ignore includes and ...
|
||
|
p = NULL;
|
||
|
break; // get next line
|
||
|
}
|
||
|
p += 2;
|
||
|
AsnState &= ~ASN_CONTINUATION;
|
||
|
}
|
||
|
moreasn:
|
||
|
while (p != NULL) {
|
||
|
while (isspace(*p)) {
|
||
|
p++;
|
||
|
}
|
||
|
if (*p == '\0') {
|
||
|
AsnState |= ASN_CONTINUATION;
|
||
|
goto nextline; // get next line
|
||
|
}
|
||
|
switch (AsnState) {
|
||
|
case ASN_NONE:
|
||
|
AsnState = ASN_START;
|
||
|
continue; // re-enter state machine
|
||
|
|
||
|
case ASN_START:
|
||
|
if (!IsTokenPrefix0(
|
||
|
p,
|
||
|
"INCLUDES",
|
||
|
sizeof("INCLUDES") - 1)) {
|
||
|
goto terminate;
|
||
|
}
|
||
|
AsnState = ASN_FILENAME;
|
||
|
p += sizeof("INCLUDES") - 1;
|
||
|
continue; // re-enter state machine
|
||
|
|
||
|
case ASN_FILENAME:
|
||
|
if (*p != '"') {
|
||
|
goto terminate;
|
||
|
}
|
||
|
AsnState = ASN_COMMA;
|
||
|
goto parsefilename;
|
||
|
|
||
|
case ASN_COMMA:
|
||
|
if (*p == '>' && p[1] == '-' && p[2] == '-') {
|
||
|
goto terminate;
|
||
|
}
|
||
|
if (*p != ',') {
|
||
|
goto terminate;
|
||
|
}
|
||
|
p++;
|
||
|
AsnState = ASN_FILENAME;
|
||
|
continue; // re-enter state machine
|
||
|
}
|
||
|
assert(FALSE); // Bad AsnState
|
||
|
terminate:
|
||
|
AsnState = ASN_NONE; // ignore includes statement, & ...
|
||
|
nextline:
|
||
|
p = NULL; // get next line
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
parsefilename:
|
||
|
if (p != NULL) {
|
||
|
CloseQuote = (UCHAR) 0xff;
|
||
|
if (*p == '<') {
|
||
|
p++;
|
||
|
CloseQuote = '>';
|
||
|
}
|
||
|
else
|
||
|
if (*p == '"') {
|
||
|
p++;
|
||
|
IncFlagsNew |= INCLUDEDB_LOCAL;
|
||
|
CloseQuote = '"';
|
||
|
}
|
||
|
else
|
||
|
if (FileDB->FileFlags & FILEDB_MASM) {
|
||
|
IncFlagsNew |= INCLUDEDB_LOCAL;
|
||
|
CloseQuote = ';';
|
||
|
}
|
||
|
|
||
|
IncludeFileName = p;
|
||
|
while (*p != '\0' && *p != CloseQuote && *p != ' ') {
|
||
|
p++;
|
||
|
}
|
||
|
if (CloseQuote == ';' && (*p == ' ' || *p == '\0')) {
|
||
|
CloseQuote = *p;
|
||
|
}
|
||
|
|
||
|
if (*p != CloseQuote || CloseQuote == (UCHAR) 0xff) {
|
||
|
BuildError(
|
||
|
"%s - invalid include statement: %s\n",
|
||
|
FormatPathName(FileDB->Dir->Name, FileDB->Name),
|
||
|
TextLine);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
*p = '\0';
|
||
|
CopyString(IncludeFileName, IncludeFileName, TRUE);
|
||
|
for (i = 0; i < CountExcludeIncs; i++) {
|
||
|
if (!strcmp(IncludeFileName, ExcludeIncs[i])) {
|
||
|
IncludeFileName = NULL;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (IncludeFileName != NULL) {
|
||
|
InsertIncludeDB(FileDB, IncludeFileName, IncFlagsNew);
|
||
|
}
|
||
|
if (FileDB->FileFlags & FILEDB_ASN) {
|
||
|
p++;
|
||
|
goto moreasn;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
if (IncFlags == 0 &&
|
||
|
(FileDB->FileFlags & (FILEDB_ASM | FILEDB_MASM | FILEDB_MIDL | FILEDB_ASN | FILEDB_RC | FILEDB_HEADER)) == 0 &&
|
||
|
IsPragmaHdrStop(TextLine)) {
|
||
|
|
||
|
IncFlags = INCLUDEDB_POST_HDRSTOP;
|
||
|
}
|
||
|
}
|
||
|
CloseReadFile(&cline);
|
||
|
FileDB->SourceLines = cline;
|
||
|
|
||
|
DeleteIncludeFileRecords( FileDB );
|
||
|
|
||
|
if (!RecurseLevel) {
|
||
|
ClearLine();
|
||
|
}
|
||
|
return(TRUE);
|
||
|
}
|