//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 1993. // // File: buildsrc.c // // Contents: Functions used to process SOURCES and DIRS files // // History: 16-May-89 SteveWo Created // 26-Jul-94 LyleC Split out from buildmak.c // //---------------------------------------------------------------------------- #include "build.h" // // Definitions used by the macro functions // #define LPAREN '(' #define RPAREN ')' // Legal character for a macro name. #define MACRO_CHAR(ch) iscsym(ch) #define CMACROMAX 1000 // maximum unique macros per sources/dirs file typedef struct _MACRO { LPSTR pszValue; UCHAR szName[1]; } MACRO; MACRO *apMacro[CMACROMAX]; UINT cMacro = 0; LPSTR *ppCurrentDirsFileName; DWORD StartTime; #define SOURCES_TARGETNAME 0 #define SOURCES_TARGETPATH 1 #define SOURCES_TARGETPATHLIB 2 #define SOURCES_TARGETTYPE 3 #define SOURCES_TARGETEXT 4 #define SOURCES_INCLUDES 5 #define SOURCES_NTTEST 6 #define SOURCES_UMTYPE 7 #define SOURCES_UMTEST 8 #define SOURCES_OPTIONAL_UMTEST 9 #define SOURCES_UMAPPL 10 #define SOURCES_UMAPPLEXT 11 #define SOURCES_NTTARGETFILE0 12 #define SOURCES_NTTARGETFILES 13 #define SOURCES_PRECOMPILED_INCLUDE 14 #define SOURCES_PRECOMPILED_PCH 15 #define SOURCES_PRECOMPILED_OBJ 16 #define SOURCES_PRECOMPILED_TARGET 17 #define SOURCES_CHICAGO_PRODUCT 18 #define SOURCES_CONDITIONAL_INCLUDES 19 #define SOURCES_SYNCHRONIZE_BLOCK 20 #define SOURCES_SYNCHRONIZE_DRAIN 21 #define SOURCES_PASS0_SOURCEDIR 22 #define SOURCES_PASS0_HEADERDIR 23 #define SOURCES_MIDL_UUIDDIR 24 #define SOURCES_PASS0_CLIENTDIR 25 #define SOURCES_PASS0_SERVERDIR 26 #define SOURCES_IDLTYPE 27 #define SOURCES_SOURCES_OPTIONS 28 #define SOURCES_MFC_INCLUDES 29 #define SOURCES_SDK_LIB_DEST 30 #define SOURCES_DDK_LIB_DEST 31 #define SOURCES_SDK_INC_PATH 32 #define SOURCES_CRT_INC_PATH 33 #define SOURCES_OAK_INC_PATH 34 #define SOURCES_DDK_INC_PATH 35 #define SOURCES_WDM_INC_PATH 36 #define SOURCES_PRIVATE_INC_PATH 37 #define SOURCES_CHECKED_ALT_DIR 38 #define SOURCES_PROJECT_NAME 39 #define SOURCES_PASS0_PUBLISH 40 LPSTR RelevantSourcesMacros[] = { "TARGETNAME", "TARGETPATH", "TARGETPATHLIB", "TARGETTYPE", "TARGETEXT", "INCLUDES", "NTTEST", "UMTYPE", "UMTEST", "OPTIONAL_UMTEST", "UMAPPL", "UMAPPLEXT", "NTTARGETFILE0", "NTTARGETFILES", "PRECOMPILED_INCLUDE", "PRECOMPILED_PCH", "PRECOMPILED_OBJ", "PRECOMPILED_TARGET", "CHICAGO_PRODUCT", "CONDITIONAL_INCLUDES", "SYNCHRONIZE_BLOCK", "SYNCHRONIZE_DRAIN", "PASS0_SOURCEDIR", "PASS0_HEADERDIR", "MIDL_UUIDDIR", "PASS0_CLIENTDIR", "PASS0_SERVERDIR", "IDL_TYPE", "SOURCES_OPTIONS", "MFC_INCLUDES", "SDK_LIB_DEST", "DDK_LIB_DEST", "SDK_INC_PATH", "CRT_INC_PATH", "OAK_INC_PATH", "DDK_INC_PATH", "WDM_INC_PATH", "PRIVATE_INC_PATH", "CHECKED_ALT_DIR", "_PROJECT_", "PASS0_PUBLISH", NULL }; #define SOURCES_MAX \ (sizeof(RelevantSourcesMacros)/sizeof(RelevantSourcesMacros[0]) - 1) VOID MarkDirNames(PDIRREC DirDB, LPSTR TextLine, BOOL Required); //+--------------------------------------------------------------------------- // // Function: CompressBlanks // // Synopsis: Compress multiple blank characters out of macro value, in // place. // // Arguments: [psrc] -- String to compress // // Notes: Note that tabs, CRs, continuation lines (and their line // breaks) have already been replaced with blanks. // //---------------------------------------------------------------------------- VOID CompressBlanks(LPSTR psrc) { LPSTR pdst = psrc; while (*psrc == ' ') { psrc++; // skip leading macro value blanks } while (*psrc != '\0') { if (*psrc == '#') { // stop at comment break; } if ((*pdst++ = *psrc++) == ' ') { while (*psrc == ' ') { psrc++; // skip multiple blanks } } } *pdst = '\0'; // terminate the compressed copy if (*--pdst == ' ') { *pdst = '\0'; // trim trailing macro value blanks } } //+--------------------------------------------------------------------------- // // Function: GetBaseDir // // Synopsis: Return the value of BASEDIR, the base NT directory, if // appropriate. // // Arguments: [pname] -- path to split // //---------------------------------------------------------------------------- LPSTR GetBaseDir(LPSTR pname) { if (_stricmp("BASEDIR", pname) == 0) { return(NtRoot); } return(NULL); } //+--------------------------------------------------------------------------- // // Function: FindMacro // // Synopsis: Returns the value of a given macro by name. // // Arguments: [pszName] -- Name of macro who's value is desired. // // Returns: String containing the value of the macro // //---------------------------------------------------------------------------- LPSTR FindMacro(LPSTR pszName) { MACRO **ppm; for (ppm = apMacro; ppm < &apMacro[cMacro]; ppm++) { if (_stricmp(pszName, (*ppm)->szName) == 0) { return((*ppm)->pszValue); } } return(NULL); } //+--------------------------------------------------------------------------- // // Function: SaveMacro // // Synopsis: Save the value of a macro // // Arguments: [pszName] -- Name of macro to save // [pszValue] -- Value of macro // // Notes: A new string must be allocated and initialized prior to // freeing the old string when updating a macro value. // //---------------------------------------------------------------------------- VOID SaveMacro(LPSTR pszName, LPSTR pszValue) { MACRO **ppm; for (ppm = apMacro; ppm < &apMacro[cMacro]; ppm++) { if (_stricmp(pszName, (*ppm)->szName) == 0) { break; } } if (ppm == &apMacro[CMACROMAX]) { BuildError("Macro table full, ignoring: %s = %s\n", pszName, pszValue); return; } if (ppm == &apMacro[cMacro]) { cMacro++; AllocMem(sizeof(MACRO) + strlen(pszName), ppm, MT_MACRO); strcpy((*ppm)->szName, pszName); (*ppm)->pszValue = NULL; } MakeMacroString(&(*ppm)->pszValue, pszValue); if (DEBUG_1) { BuildMsg( "SaveMacro(%s = %s)\n", (*ppm)->szName, (*ppm)->pszValue == NULL? "NULL" : (*ppm)->pszValue); } if ((*ppm)->pszValue == NULL) { FreeMem(ppm, MT_MACRO); *ppm = apMacro[--cMacro]; } } //+--------------------------------------------------------------------------- // // Function: FreeMacros // // Synopsis: Free all macros // // Arguments: (none) // //---------------------------------------------------------------------------- VOID FreeMacros(VOID) { MACRO **ppm; for (ppm = apMacro; ppm < &apMacro[cMacro]; ppm++) { FreeString(&(*ppm)->pszValue, MT_DIRSTRING); FreeMem(ppm, MT_MACRO); assert(*ppm == NULL); } cMacro = 0; } //+--------------------------------------------------------------------------- // // Function: SplitMacro // // Synopsis: Take a string containing "MACRONAME = VALUE" and return // the target and value. // // Arguments: [pline] -- String to split and target return. // // Returns: Value of macro. // //---------------------------------------------------------------------------- LPSTR SplitMacro(LPSTR *pszTarget) { LPSTR pvalue, p, pline; pvalue = NULL; pline = *pszTarget; // Quickly reject comments and ! directives. if (*pline == '#' || *pline == '!') { return NULL; } if ((p = strchr(pline, '=')) != NULL) { pvalue = p + 1; // point past old '=' while (p > pline && p[-1] == ' ') { p--; // point to start of trailing blanks } // Check for missing target. if (p == pline) { return NULL; } *p = '\0'; // trim trailing blanks & '=' // Perform macro substitution on target. *pszTarget = NULL; if (!MakeMacroString(pszTarget, pline)) { return NULL; } // Validate target name. If must be a non-empty string of // valid macro name characters. if (**pszTarget == 0) { FreeString(pszTarget, MT_DIRSTRING); return NULL; } for (p = *pszTarget; *p != 0; p++) { if (!MACRO_CHAR(*p)) { FreeString(pszTarget, MT_DIRSTRING); return NULL; } } CompressBlanks(pvalue); } return(pvalue); } //+--------------------------------------------------------------------------- // // Function: SubstituteString // // Synopsis: Perform any macro substitution. This code was copied from the // nmake source. // // Arguments: // // Returns: // // Notes: // //---------------------------------------------------------------------------- void SubstituteString( char **result, char **name, char **dest, char **end, char *source, unsigned *length ) { #define ESCH '^' char *oldString, *newString; char *pEq, *pPar, *t; char *s; unsigned i; ++*name; for (pEq = *name; *pEq && *pEq != '='; pEq++) if (*pEq == ESCH) pEq++; // Did we find the '=' sign? if (*pEq != '=') printf("Error1\n"); // Did the user forget the initial string? if (pEq == *name) printf("Error2\n"); for (pPar = pEq; *pPar && *pPar != ')'; pPar++) if (*pPar == ESCH) pPar++; if (*pPar != ')') printf("Error3\n"); oldString = (char *)malloc((UINT)((pEq - *name) + 1)); if (!oldString) { BuildError("(Fatal Error) Out Of Memory: SubstituteString()\n"); exit(16); } for (s = oldString, t = *name; *t != '='; *s++ = *t++) if (*t == ESCH) ++t; *s = '\0'; i = strlen(oldString); newString = (char *)malloc((UINT)(pPar - pEq)); if (!newString) { BuildError("(Fatal Error) Out Of Memory: SubstituteString()\n"); exit(16); } for (s = newString, t++; *t != ')'; *s++ = *t++) if (*t == ESCH) ++t; *s = '\0'; *name = pPar + 1; while (*source) { if ((*source == *oldString) // check for match && !strncmp(source, oldString, i)) { // copy new in for for (s = newString; *s; *(*dest)++ = *s++) // old string if (*dest == *end) { *result = realloc(*result, *length + 100); if (!*result) { BuildError("(Fatal Error) Out Of Memory: SubstituteString()\n"); exit(16); } *dest = *result + *length; *length += 100; *end = *result + *length; } source += i; continue; } if (*dest == *end) { *result = realloc(*result, *length + 100); if (!*result) { BuildError("(Fatal Error) Out Of Memory: SubstituteString()\n"); exit(16); } *dest = *result + *length; *length += 100; *end = *result + *length; } *(*dest)++ = *source++; // else copy 1 char } free(oldString); free(newString); } //+--------------------------------------------------------------------------- // // Function: MakeMacroString // // Synopsis: Take a string, and expand any macros in it. (e.g. // "$(BASEDIR)\foobar\myfile.lib" is expanded to // "f:\nt\private\foobar\myfile.lib" if $(BASEDIR) has a value of // "f:\nt\private". // // Arguments: [pp] -- Output string // [psrc] -- Input string // // Returns: // // Notes: Any previous string value in [pp] is freed before updating it. // //---------------------------------------------------------------------------- char MMSBuffer[64*1024]; BOOL MakeMacroString(LPSTR *pp, LPSTR psrc) { LPSTR pname, p2, pdst, p3; int cb; char chTerminator; int cNameChars; int cChars; pdst = MMSBuffer; cb = strlen(psrc); if (cb > sizeof(MMSBuffer) - 1) { BuildError( "(Fatal Error) Buffer overflow: MakeMacroString(%s)\n", psrc); exit(16); } while ((pname = strchr(psrc, '$')) != NULL && ((pname[1] == LPAREN && (p2 = strchr(pname, RPAREN)) != NULL) || (MACRO_CHAR(pname[1]) && !MACRO_CHAR(pname[2])))) { LPSTR pszvalue; // Handle one-character non-paren macro usage. if (pname[1] == LPAREN) { // Initialize cNameChars with the number of chars to // skip to get to the first name character. cNameChars = 2; } else { p2 = pname + 2; cNameChars = 1; } chTerminator = *p2; *pname = *p2 = '\0'; // copy up to macro name cChars = strlen(psrc); memcpy(pdst, psrc, cChars + 1); psrc += cChars; pdst += cChars; *pname = '$'; pname += cNameChars; cNameChars += strlen(pname) + (chTerminator == RPAREN ? 1 : 0); p3 = NULL; if (chTerminator == RPAREN && (p3 = strchr(pname, ':')) != NULL) { // macro substitution exists. ie: $(foo:old=new) *p3 = '\0'; } if ((pszvalue = FindMacro(pname)) == NULL && (pszvalue = getenv(pname)) == NULL && (pszvalue = GetBaseDir(pname)) == NULL) { pszvalue = ""; // can't find macro name -- ignore it } if (p3) { char *pNew = malloc(10); char *pResult = pNew; char *pEnd = pNew+10; unsigned Len = 10; if (!pNew) { BuildError("(Fatal Error) Internal buffer overflow: MakeMacroString(%s[%s = %s]%s)\n", MMSBuffer, pname, pszvalue, p2 + 1); exit(16); } *p3 = ':'; *p2=RPAREN; SubstituteString(&pResult, &p3, &pNew, &pEnd, pszvalue, &Len); *pNew = '\0'; *p2='\0'; pszvalue = pResult; } cb += strlen(pszvalue) - cNameChars; assert(cb >= 0); if (cb > sizeof(MMSBuffer) - 1) { BuildError( "(Fatal Error) Internal buffer overflow: MakeMacroString(%s[%s = %s]%s)\n", MMSBuffer, pname, pszvalue, p2 + 1); exit(16); } strcpy(pdst, pszvalue); // copy expanded value if (p3) { free(pszvalue); } pdst += strlen(pdst); *p2 = chTerminator; psrc += cNameChars; } strcpy(pdst, psrc); // copy rest of string if (pdst != MMSBuffer) { CompressBlanks(MMSBuffer); } p2 = *pp; *pp = NULL; if (MMSBuffer[0] != '\0') { MakeString(pp, MMSBuffer, TRUE, MT_DIRSTRING); } if (p2 != NULL) { FreeMem(&p2, MT_DIRSTRING); } return(MMSBuffer[0] != '\0'); } //+--------------------------------------------------------------------------- // // Function: SetMacroString // // Synopsis: If the two macro names are the same, store the value in that // macro // // Arguments: [pMacro1] -- Name of first macro // [pMacro2] -- Name of second macro // [pValue] -- Unexpanded value to store. // [ppValue] -- Expanded value of macro. // // Returns: BOOL // //---------------------------------------------------------------------------- BOOL SetMacroString(LPSTR pMacro1, LPSTR pMacro2, LPSTR pValue, LPSTR *ppValue) { if (_stricmp(pMacro1, pMacro2) == 0) { MakeMacroString(ppValue, pValue); return(TRUE); // return TRUE even if MakeMacroString stored a NULL } return(FALSE); } //+--------------------------------------------------------------------------- // // Function: SplitToken // // Synopsis: Split the string at the given separator character or space. // // Arguments: [pbuf] -- First part of split string returned here. // [chsep] -- Separator character. // [ppstr] -- Source string to split. Becomes the second half. // // Returns: TRUE if the split was successful. FALSE if it wasn't split. // // Notes: If *ppstr = "path\filename" and chsep = '\' on input, then // pbuf = "path" and *ppstr = "\filename" on output. // //---------------------------------------------------------------------------- BOOL SplitToken(LPSTR pbuf, char chsep, LPSTR *ppstr) { LPSTR psrc, pdst; psrc = *ppstr; pdst = pbuf; //BuildError("SplitToken('%c', '%s') ==> ", chsep, psrc); while (*psrc == chsep || *psrc == ' ') { psrc++; } while (*psrc != '\0' && *psrc != chsep && *psrc != ' ') { *pdst = *psrc++; if (*pdst == '/') { *pdst = '\\'; } pdst++; } *pdst = '\0'; *ppstr = psrc; //BuildErrorRaw("('%s', '%s')\n", psrc, pbuf); return(pdst != pbuf); } //+--------------------------------------------------------------------------- // // Function: CrackSources // // Synopsis: Parse the SOURCES= line in a sources file and adds those source // files to the list of sources in the DIRREC struct. // // Arguments: [pdr] -- Directory record // [pds] -- Supplemental directory information // [i] -- Which platform we're parsing // //---------------------------------------------------------------------------- VOID CrackSources( DIRREC *pdr, DIRSUP *pds, int i) { LPSTR pszsubdir, plist; LPSTR pszfile, pszpath; FILEREC *pfr; DIRREC *pdrAssociate; DIRREC *pdrParent; DIRREC *pdrMachine; DIRREC *pdrParentMachine; DIRREC *pdrTarget; DIRREC **ppdr; LPSTR pszSources; char path[DB_MAX_PATH_LENGTH]; TARGET_MACHINE_INFO *pMachine; if (i == 0) { pMachine = TargetMachines[0]; pszSources = "SOURCES"; } else { pMachine = PossibleTargetMachines[i - 1]; pszSources = pMachine->SourceVariable; } pdrAssociate = pdrParent = pdrMachine = pdrParentMachine = pdrTarget = NULL; plist = pds->SourcesVariables[i]; while (SplitToken(path, ' ', &plist)) { UCHAR SubDirMask, SrcFlags; SubDirMask = 0; ppdr = &pdr; // assume current directory pszsubdir = path; if (pszsubdir[0] == '.' && pszsubdir[1] == '\\') { BuildError( "%s: Ignoring current directory prefix in %s= entry: %s\n", pdr->Name, pszSources, path); pszsubdir += 2; } if (pszsubdir[0] == '.' && pszsubdir[1] == '.' && pszsubdir[2] == '\\') { SubDirMask = TMIDIR_PARENT; ppdr = &pdrParent; // assume parent directory pszsubdir += 3; } pszpath = path; pszfile = strchr(pszsubdir, '\\'); if (pszfile == NULL) { pszfile = pszsubdir; } else { LPSTR pszSecondSlash; LPSTR pszAssociateDir; LPSTR pszMachineDir; // Check for second slash and handle $O\. If there is // no second slash, check for a machine specific directory name. // Second slashes are not legal if there's already been // a '..'. if ((SubDirMask & TMIDIR_PARENT) == 0) { pszSecondSlash = strchr(pszfile + 1, '\\'); if (pszSecondSlash != NULL) { pszfile = pszSecondSlash; } } else { pszSecondSlash = NULL; } *pszfile = '\0'; if (pszSecondSlash != NULL) { pszMachineDir = pMachine->ObjectDirectory[iObjectDir]; pszAssociateDir = pszMachineDir; } else { pszMachineDir = pMachine->SourceDirectory; pszAssociateDir = pMachine->AssociateDirectory; } if (((_stricmp(pszsubdir, pszAssociateDir) != 0) && (_stricmp(pszsubdir, pszMachineDir) != 0)) || strchr(pszfile + 1, '\\') != NULL) { *pszfile = '\\'; BuildError( "%s: Ignoring invalid directory prefix in %s= entry: %s\n", pdr->Name, pszSources, path); // pszpath = strrchr(path, '\\'); assert(pszpath != NULL); pszpath++; SubDirMask = 0; ppdr = &pdr; // default to current direcory } else { SubDirMask |= pMachine->SourceSubDirMask; *pszfile++ = '\\'; if (SubDirMask & TMIDIR_PARENT) { ppdr = &pdrParentMachine; } else if (pszSecondSlash != NULL) { // Must have matched $O. ppdr = &pdrTarget; } else { if (_stricmp(pszsubdir, pszMachineDir) != 0) { ppdr = &pdrMachine; } else { ppdr = &pdrAssociate; } } } } NewDirectory: if (*ppdr == NULL) { pfr = FindSourceFileDB(pdr, pszpath, ppdr); } else { pfr = LookupFileDB(*ppdr, pszfile); } SrcFlags = SOURCEDB_SOURCES_LIST; if ((pfr == NULL) && !fPassZero) { if (fDebug) { BuildError("%s: Missing source file: %s\n", pdr->Name, path); } if (*ppdr == NULL) { if (fDebug || pszpath == path) { BuildError( "%s: Directory does not exist: %s\n", pdr->Name, path); } // Probably an error in the subordinate sources file. // since old versions of build managed to get these entries // into the objects lists, we have to do the same... // // If ..\ prefix exists, strip it off and try again. // Else try again with the current directory. if (SubDirMask & TMIDIR_PARENT) { SubDirMask &= ~TMIDIR_PARENT; // strip off "..\\" } else { SubDirMask = 0; // use current direcory } if (SubDirMask == 0) { ppdr = &pdr; // current direcory pszpath = pszfile; } else { ppdr = &pdrMachine; // machine sub dir pszpath = pszsubdir; } goto NewDirectory; } pfr = InsertFileDB(*ppdr, pszfile, 0, 0, FILEDB_FILE_MISSING); if (pfr == NULL) { BuildError( "%s: Ignoring invalid %s= entry: %s\n", pdr->Name, pszSources, path); } } if (pfr != NULL) { AssertFile(pfr); if (SubDirMask == 0) { pfr->FileFlags |= FILEDB_OBJECTS_LIST; } if (pfr->FileFlags & FILEDB_FILE_MISSING) { SrcFlags |= SOURCEDB_FILE_MISSING; } InsertSourceDB(&pds->psrSourcesList[i], pfr, SubDirMask, SrcFlags); } } } //+--------------------------------------------------------------------------- // // Function: SaveUserTests // // Synopsis: Save the value of the UMTEST macro into the DIRREC struct. // // Arguments: [DirDB] -- Dir struct to save into // [TextLine] -- String from UMTEST= line in sources file // //---------------------------------------------------------------------------- VOID SaveUserTests( PDIRREC DirDB, LPSTR TextLine) { UINT i; BOOL fSave = FALSE; char name[DB_MAX_PATH_LENGTH]; char buf[512]; buf[0] = '\0'; if (DirDB->UserTests != NULL) { strcpy(buf, DirDB->UserTests); } CopyString(TextLine, TextLine, TRUE); while (SplitToken(name, '*', &TextLine)) { for (i = 0; i < CountOptionalDirs; i++) { if (!strcmp(name, OptionalDirs[i])) { if (buf[0] != '\0') { strcat(buf, "*"); DirDB->DirFlags |= DIRDB_FORCELINK; // multiple targets } strcat(buf, name); fSave = TRUE; break; } } } if (fSave) { MakeMacroString(&DirDB->UserTests, buf); DirDB->DirFlags |= DIRDB_LINKNEEDED; } } //+--------------------------------------------------------------------------- // // Function: ProcessSourcesFileLine // // Synopsis: Given a line from a sources file, do the right thing. // // Arguments: [DirDB] -- Directory containing sources file // [pds] -- Supplementary info on directory // [TextLine] -- Line to process // // Returns: void // //---------------------------------------------------------------------------- void ProcessSourcesFileLine( DIRREC *DirDB, // Current Directory record DIRSUP *pds, // Supplemental Directory record LPSTR TextLine, // Line to process int iTarget // Index into target machine array. ) { LPSTR MacroName, p1; UINT i, iMacro; char path[DB_MAX_PATH_LENGTH]; BOOL fCleanNTTargetFile0 = FALSE; LPSTR pValue; // right side of equal sign pValue = SplitMacro(&TextLine); if (pValue == NULL) { return; } // Note: TextLine is now the left side of the equal sign. See if it's interesting. // // This sets pds->SourcesVariables[0] to the value of SOURCES= if // the current line is SOURCES=... // if (SetMacroString( "SOURCES", TextLine, pValue, &pds->SourcesVariables[0])) { DirDB->DirFlags |= DIRDB_SOURCES_SET; goto SaveAndFreeMacro; } else { for (i = 0; i < MAX_TARGET_MACHINES; i++) { // // This sets pds->SourcesVariables[0] to the value of // PLAT_SOURCES= if the current line is PLAT_SOURCES=... // if (SetMacroString( PossibleTargetMachines[i]->SourceVariable, TextLine, pValue, &pds->SourcesVariables[i + 1])) { DirDB->DirFlags |= DIRDB_SOURCES_SET; goto SaveAndFreeMacro; } } } // Not a SOURCES or xxx_SOURCES macro, check against all the other interesting // macro names. iMacro = 0; while ((MacroName = RelevantSourcesMacros[iMacro]) != NULL) { if (_stricmp(TextLine, MacroName) == 0) { break; } iMacro++; } if (MacroName != NULL) { // if macro name found in list switch (iMacro) { case SOURCES_TARGETNAME: MakeMacroString(&DirDB->TargetName, pValue); break; case SOURCES_TARGETPATH: if (strcmp(pValue, "obj") == 0) { pValue = pszObjDir; } MakeMacroString(&DirDB->TargetPath, pValue); if (DirDB->TargetPath != NULL) { CreateBuildDirectory(DirDB->TargetPath); for (i = 0; i < CountTargetMachines; i++) { p1 = TargetMachines[i]->ObjectDirectory[iObjectDir]; assert(strncmp(pszObjDirSlash, p1, strlen(pszObjDirSlash)) == 0); p1 += strlen(pszObjDirSlash); sprintf(path, "%s\\%s", DirDB->TargetPath, p1); CreateBuildDirectory(path); } } break; case SOURCES_TARGETPATHLIB: if (strcmp(pValue, "obj") == 0) { pValue = pszObjDir; } MakeMacroString(&DirDB->TargetPathLib, pValue); if (DirDB->TargetPathLib != NULL) { CreateBuildDirectory(DirDB->TargetPathLib); for (i = 0; i < CountTargetMachines; i++) { p1 = TargetMachines[i]->ObjectDirectory[iObjectDir]; assert(strncmp(pszObjDirSlash, p1, strlen(pszObjDirSlash)) == 0); p1 += strlen(pszObjDirSlash); sprintf(path, "%s\\%s", DirDB->TargetPathLib, p1); CreateBuildDirectory(path); } } break; case SOURCES_TARGETTYPE: if (!_stricmp(pValue, "PROGRAM") || !_stricmp(pValue, "PROGLIB")) { MakeMacroString(&DirDB->TargetExt, ".exe"); DirDB->DirFlags |= DIRDB_LINKNEEDED; } else if (!_stricmp(pValue, "OBJLIB")) { MakeMacroString(&DirDB->TargetExt, ".olb"); DirDB->DirFlags |= DIRDB_LINKNEEDED; } else if (!_stricmp(pValue, "DRIVER") || !_stricmp(pValue, "MINIPORT")) { MakeMacroString(&DirDB->TargetExt, ".sys"); DirDB->DirFlags |= DIRDB_LINKNEEDED; } else if (!_stricmp(pValue, "GDI_DRIVER")) { MakeMacroString(&DirDB->TargetExt, ".dll"); DirDB->DirFlags |= DIRDB_LINKNEEDED; } else if (!_stricmp(pValue, "EXPORT_DRIVER")) { MakeMacroString(&DirDB->TargetExt, ".sys"); DirDB->DirFlags |= DIRDB_LINKNEEDED; DirDB->DirFlags |= DIRDB_DLLTARGET; } else if (!_stricmp(pValue, "DYNLINK") || !_stricmp(pValue, "HAL")) { MakeMacroString(&DirDB->TargetExt, ".dll"); DirDB->DirFlags |= DIRDB_LINKNEEDED; DirDB->DirFlags |= DIRDB_DLLTARGET; } else if ((!_stricmp(pValue, "LIBRARY")) || (!_stricmp(pValue, "DRIVER_LIBRARY"))) { MakeMacroString(&DirDB->TargetExt, ".lib"); DirDB->DirFlags &= ~DIRDB_LINKNEEDED; } else if (!_stricmp(pValue, "UMAPPL_NOLIB")) { DirDB->DirFlags &= ~DIRDB_LINKNEEDED; } else if (!_stricmp(pValue, "NOTARGET")) { // // Used to indicate no target for a directory, // e.g. if only pass0 files are generated pds->fNoTarget = TRUE; if (!fQuicky || (fQuickZero && fFirstScan)) { DirDB->DirFlags |= DIRDB_PASS0NEEDED; } } else { BuildError( "Unsupported TARGETTYPE value - %s\n", pValue); } break; case SOURCES_TARGETEXT: { char TargetExt[_MAX_EXT] = "."; strcat(TargetExt, pValue); MakeMacroString(&DirDB->TargetExt, TargetExt); } break; case SOURCES_INCLUDES: MakeMacroString(&pds->LocalIncludePath, pValue); if (DEBUG_1) { BuildMsg( " Found local INCLUDES=%s\n", pds->LocalIncludePath); } break; case SOURCES_MFC_INCLUDES: // MFC_INCLUDES/SDK_INC/CRT_INC/OAK_INC really can't be changed // in the sources file (yet) since we've already processed the // system includes. Lay the groundwork for now. MakeMacroString((char **)&pszIncMfc, pValue); break; case SOURCES_SDK_LIB_DEST: MakeMacroString((char **)&pszSdkLibDest, pValue); break; case SOURCES_DDK_LIB_DEST: MakeMacroString((char **)&pszDdkLibDest, pValue); break; case SOURCES_SDK_INC_PATH: MakeMacroString((char **)&pszIncSdk, pValue); break; case SOURCES_CRT_INC_PATH: MakeMacroString((char **)&pszIncCrt, pValue); break; case SOURCES_OAK_INC_PATH: MakeMacroString((char **)&pszIncOak, pValue); break; case SOURCES_DDK_INC_PATH: MakeMacroString((char **)&pszIncDdk, pValue); break; case SOURCES_WDM_INC_PATH: MakeMacroString((char **)&pszIncWdm, pValue); break; case SOURCES_PRIVATE_INC_PATH: MakeMacroString((char **)&pszIncPri, pValue); break; case SOURCES_PRECOMPILED_PCH: MakeMacroString(&DirDB->Pch, pValue); break; case SOURCES_PRECOMPILED_OBJ: MakeMacroString(&DirDB->PchObj, pValue); break; case SOURCES_PRECOMPILED_INCLUDE: case SOURCES_PRECOMPILED_TARGET: { LPSTR *ppszPath, *ppszFile, p; if (iMacro == SOURCES_PRECOMPILED_INCLUDE) { ppszPath = &pds->PchIncludeDir; ppszFile = &pds->PchInclude; } else { ppszPath = &pds->PchTargetDir; ppszFile = &pds->PchTarget; } MakeMacroString(ppszPath, ""); // free old string if (!MakeMacroString(ppszFile, pValue)) { break; } p = *ppszFile + strlen(*ppszFile); while (p > *ppszFile && *--p != '\\') ; if (p > *ppszFile) { *p = '\0'; MakeMacroString(ppszPath, *ppszFile); MakeMacroString(ppszFile, p + 1); } if (DEBUG_1) { BuildMsg( "Precompiled header%s is %s in directory %s\n", iMacro == SOURCES_PRECOMPILED_INCLUDE? "" : " target", *ppszFile, *ppszPath != NULL? *ppszPath : "'.'"); } } if (iMacro == SOURCES_PRECOMPILED_INCLUDE || pds->PchTargetDir == NULL) { break; } EnsureDirectoriesExist(pds->PchTargetDir); break; case SOURCES_PASS0_HEADERDIR: MakeMacroString(&pds->PassZeroHdrDir, pValue); EnsureDirectoriesExist(pds->PassZeroHdrDir); if (DEBUG_1) { BuildMsg("Pass Zero Header Directory is '%s'\n", pds->PassZeroHdrDir); } break; case SOURCES_PASS0_SOURCEDIR: case SOURCES_PASS0_CLIENTDIR: // SOURCES_PASS0_SOURCEDIR and SOURCES_PASS0_CLIENTDIR // are mutually exclusive - enforced by makefile.def MakeMacroString(&pds->PassZeroSrcDir1, pValue); EnsureDirectoriesExist(pds->PassZeroSrcDir1); if (DEBUG_1) { BuildMsg("Pass Zero Source/Client Directory is '%s'\n", pds->PassZeroSrcDir1); } break; case SOURCES_MIDL_UUIDDIR: case SOURCES_PASS0_SERVERDIR: // SOURCES_MIDL_UUIDDIR and SOURCES_PASS0_SERVERDIR // are mutually exclusive - enforced by makefile.def MakeMacroString(&pds->PassZeroSrcDir2, pValue); EnsureDirectoriesExist(pds->PassZeroSrcDir2); if (DEBUG_1) { BuildMsg("Midl UUID/Server Source Directory is '%s'\n", pds->PassZeroSrcDir2); } break; case SOURCES_NTTEST: if (MakeMacroString(&DirDB->KernelTest, pValue)) { DirDB->DirFlags |= DIRDB_LINKNEEDED; } break; case SOURCES_UMTYPE: MakeMacroString(&pds->TestType, pValue); if (DEBUG_1) { BuildMsg( " Found UMTYPE=%s\n", pds->TestType); } break; case SOURCES_UMTEST: case SOURCES_OPTIONAL_UMTEST: SaveUserTests(DirDB, pValue); break; case SOURCES_UMAPPL: if (MakeMacroString(&DirDB->UserAppls, pValue)) { DirDB->DirFlags |= DIRDB_LINKNEEDED; } break; case SOURCES_UMAPPLEXT: if (!_stricmp(pValue, ".exe")) { MakeMacroString(&DirDB->TargetExt, ".exe"); } else if (!_stricmp(pValue, ".com")) { MakeMacroString(&DirDB->TargetExt, ".com"); } else if (!_stricmp(pValue, ".scr")) { MakeMacroString(&DirDB->TargetExt, ".scr"); } else { BuildError( "Unsupported UMAPPLEXT value - %s\n", pValue); } break; case SOURCES_IDLTYPE: if (!_stricmp(pValue, "ole")) { pds->IdlType = 0; } else if (!_stricmp(pValue, "rpc")) { pds->IdlType = 1; } else { BuildError( "Unsupported IDL_TYPE value - %s\n", pValue); } break; case SOURCES_SOURCES_OPTIONS: fCleanNTTargetFile0 = fClean && strstr(pValue, "-c0"); break; case SOURCES_NTTARGETFILE0: DirDB->DirFlags |= DIRDB_TARGETFILE0; if (fCleanNTTargetFile0) { MakeMacroString(&DirDB->NTTargetFile0, pValue); } break; case SOURCES_NTTARGETFILES: DirDB->DirFlags |= DIRDB_TARGETFILES; break; case SOURCES_CHICAGO_PRODUCT: DirDB->DirFlags |= DIRDB_CHICAGO_INCLUDES; break; case SOURCES_CONDITIONAL_INCLUDES: MakeMacroString(&pds->ConditionalIncludes, pValue); break; case SOURCES_SYNCHRONIZE_BLOCK: DirDB->DirFlags |= DIRDB_SYNCHRONIZE_BLOCK; break; case SOURCES_SYNCHRONIZE_DRAIN: DirDB->DirFlags |= DIRDB_SYNCHRONIZE_DRAIN; break; case SOURCES_CHECKED_ALT_DIR: DirDB->DirFlags |= DIRDB_CHECKED_ALT_DIR; if (DEBUG_1) { BuildMsg("Found CHECKED_ALT_DIR\n"); } SetObjDir(TRUE); if (fCheckedBuild) { SaveMacro("_OBJ_DIR", pszObjDir); if (iTarget < 0) { SaveMacro("O", TargetMachines[0]-> ObjectDirectory[iObjectDir]); } else { SaveMacro("O", PossibleTargetMachines[iTarget/2]-> ObjectDirectory[iObjectDir]); } } break; case SOURCES_PROJECT_NAME: sprintf(path, "%s\\%s", NtRoot, pValue); SaveMacro("PROJECT_ROOT", path); break; case SOURCES_PASS0_PUBLISH: DirDB->DirFlags |= DIRDB_PASS0NEEDED; break; } } SaveAndFreeMacro: SaveMacro(TextLine, pValue); // Make sure we cleanup from the SplitMacro call at the top. FreeString(&TextLine, MT_DIRSTRING); } void ReadProjectsInfo( DIRREC *DirDB, DIRSUP *pds ) { FILE *FileHandle; LPSTR TextLine, pBackSlash, pszProject; BOOL Found; char pszProjectMkPath[DB_MAX_PATH_LENGTH]; char path[DB_MAX_PATH_LENGTH]; // First load project.mk for this project. strcpy(pszProjectMkPath, DirDB->Name); strcpy(path, pszProjectMkPath); strcat(path, "\\project.mk"); Found = !_access(path, 0); while (!Found && strlen(pszProjectMkPath)) { pBackSlash=strrchr(pszProjectMkPath, '\\'); if (pBackSlash) { *pBackSlash = '\0'; } else { return; } strcpy(path, pszProjectMkPath); strcat(path, "\\project.mk"); Found = !_access(path, 0); } if (!Found) { return; } if (!OpenFilePush(pszProjectMkPath, "project.mk", "#", &FileHandle)) { return; } SaveMacro("_PROJECT_MK_PATH", pszProjectMkPath); while ((TextLine = ReadLine(FileHandle)) != NULL) { ProcessSourcesFileLine(DirDB, pds, TextLine, -1); } CloseReadFile(NULL); // Load the optional myproject.mk if (OpenFilePush(pszProjectMkPath, "myproject.mk", "#", &FileHandle)) { while ((TextLine = ReadLine(FileHandle)) != NULL) { ProcessSourcesFileLine(DirDB, pds, TextLine, -1); } CloseReadFile(NULL); } // Then load ntmakeenv\projects.inc to get the other magic macro names. if (!OpenFilePush(getenv("NTMAKEENV"), "projects.inc", "#", &FileHandle)) { return; } while ((TextLine = ReadLine(FileHandle)) != NULL) { ProcessSourcesFileLine(DirDB, pds, TextLine, -1); } CloseReadFile(NULL); } //+--------------------------------------------------------------------------- // // Function: ReadSourcesFile // // Synopsis: Parses the sources files (common and platform specific) // // Arguments: [DirDB] -- Directory containing sources file // [pds] -- Supplementary info on directory // [pDateTimeSources] -- Timestamp of Sources file // // Returns: TRUE if read successfully // //---------------------------------------------------------------------------- BOOL ReadSourcesFile(DIRREC *DirDB, DIRSUP *pds, ULONG *pDateTimeSources) { FILE *InFileHandle; LPSTR p, TextLine; UINT i; int iTarget; ULONG DateTime; char path[DB_MAX_PATH_LENGTH]; memset(pds, 0, sizeof(*pds)); pds->fNoTarget=FALSE; assert(DirDB->TargetPath == NULL); assert(DirDB->TargetPathLib == NULL); assert(DirDB->TargetName == NULL); assert(DirDB->TargetExt == NULL); assert(DirDB->KernelTest == NULL); assert(DirDB->UserAppls == NULL); assert(DirDB->UserTests == NULL); assert(DirDB->NTTargetFile0 == NULL); assert(DirDB->Pch == NULL); assert(DirDB->PchObj == NULL); assert(cMacro == 0); *pDateTimeSources = 0; // // Read the information in each of the target specific directories // and simulate concatenation of all of the sources files. // // Possible sources files are read from DirDB->Name | target-source // and DirDb->Name | ..\target-source. // // iTarget values, and the corresponding files processed are: // -1 sources. // 0 PossibleTargetMachines[0]\sources. // 1 ..\PossibleTargetMachines[0]\sources. // 2 PossibleTargetMachines[1]\sources. // 3 ..\PossibleTargetMachines[1]\sources. // 4 PossibleTargetMachines[2]\sources. // 5 ..\PossibleTargetMachines[2]\sources. SaveMacro("MAKEDIR", DirDB->Name); SaveMacro("SDK_LIB_DEST", pszSdkLibDest); SaveMacro("DDK_LIB_DEST", pszDdkLibDest); SaveMacro("PUBLIC_INTERNAL_PATH", pszPublicInternalPath); // Use the default architecture for now SaveMacro("TARGET_DIRECTORY", TargetMachines[0]->SourceDirectory); SetObjDir(FALSE); SaveMacro("_OBJ_DIR", pszObjDir); // Define a default CONDITIONAL_INCLUDES line to deal with the mac hdrs in windows/rpc/ole32.h. MakeMacroString(&pds->ConditionalIncludes, "winwlm.h rpcmac.h rpcerr.h macpub.h macapi.h macname1.h macname2.h"); // Before processing the sources file, see if there's a projects.mk in the tree. ReadProjectsInfo(DirDB, pds); for (iTarget = -1; iTarget < 2*MAX_TARGET_MACHINES; iTarget++) { path[0] = '\0'; if (iTarget >= 0) { if (iTarget & 1) { strcat(path, "..\\"); } strcat(path, PossibleTargetMachines[iTarget/2]->SourceDirectory); strcat(path, "\\"); } strcat(path, "sources."); if (!OpenFilePush(DirDB->Name, path, "#", &InFileHandle)) { if (iTarget == -1) { FreeMacros(); return(FALSE); } continue; // skip non-existent subordinate sources files } if (DEBUG_1) { BuildMsg( " Scanning%s file %s\n", iTarget >= 0 ? " subordinate" : "", FormatPathName(DirDB->Name, path)); } // Update per-target macros. if (iTarget < 0) { SaveMacro("TARGET_DIRECTORY", TargetMachines[0]->SourceDirectory); SaveMacro("O", TargetMachines[0]-> ObjectDirectory[iObjectDir]); } else { SaveMacro("TARGET_DIRECTORY", PossibleTargetMachines[iTarget/2]->SourceDirectory); SaveMacro("O", PossibleTargetMachines[iTarget/2]-> ObjectDirectory[iObjectDir]); } DirDB->DirFlags |= DIRDB_SOURCESREAD; while ((TextLine = ReadLine(InFileHandle)) != NULL) { ProcessSourcesFileLine(DirDB, pds, TextLine, iTarget); } // Subordinate files close themselves at EOF. Timestamps // are propagated in CloseReadFile so the primary // file's timestamp is automatically updated. } // Close the primary file. DateTime = CloseReadFile(NULL); if (*pDateTimeSources < DateTime) { *pDateTimeSources = DateTime; // keep newest timestamp } if (!pds->fNoTarget && (DirDB->TargetPath == NULL)) { strcpy(path, "sources."); SetupReadFile(DirDB->Name, path, "#", &InFileHandle); BuildError( "Unknown TARGETPATH value\n", NULL); CloseReadFile(NULL); } FreeMacros(); if (fChicagoProduct) { DirDB->DirFlags |= DIRDB_CHICAGO_INCLUDES; } // // Directory has pass0 files in it (.idl, .mc, .asn, etc), check to make // sure they specified where the generated files should go. Default to the // obj subdirectories if they didn't. These always need to be non-null. // if (!pds->PassZeroHdrDir) { MakeString(&pds->PassZeroHdrDir, ".", TRUE, MT_DIRSTRING); } if (!pds->PassZeroSrcDir1) { MakeString(&pds->PassZeroSrcDir1, ".", TRUE, MT_DIRSTRING); } if (!pds->PassZeroSrcDir2) MakeString(&pds->PassZeroSrcDir2, pds->PassZeroSrcDir1, TRUE, MT_DIRSTRING); if (DirDB->UserTests != NULL) { _strlwr(DirDB->UserTests); } if (DirDB->UserAppls != NULL) { if (DirDB->UserTests != NULL || strchr(DirDB->UserAppls, '*') != NULL) { DirDB->DirFlags |= DIRDB_FORCELINK; // multiple targets } } PostProcessSources(DirDB, pds); if (DEBUG_1) { PrintDirDB(DirDB, 1|2); PrintDirSupData(pds); PrintDirDB(DirDB, 4); } pds->DateTimeSources = *pDateTimeSources; return(TRUE); } //+--------------------------------------------------------------------------- // // Function: PostProcessSources // // Synopsis: Scan the files in the given directory and add files to the // directory's list of source files (SOURCEREC), including PCH // files, UMTEST files, etc. // // Arguments: [pdr] -- Directory to process // [pds] -- Directory supplemental information // //---------------------------------------------------------------------------- void PostProcessSources(DIRREC *pdr, DIRSUP *pds) { PFILEREC FileDB, *FileDBNext; char path[DB_MAX_PATH_LENGTH]; LPSTR p, p1; UINT i; for (i = 0; i < MAX_TARGET_MACHINES + 1; i++) { if (pds->SourcesVariables[i] != NULL) { CrackSources(pdr, pds, i); } } FileDBNext = &pdr->Files; while (FileDB = *FileDBNext) { if (pds->PchInclude && strcmp(FileDB->Name, pds->PchInclude) == 0) { InsertSourceDB(&pds->psrSourcesList[0], FileDB, 0, SOURCEDB_PCH); if (DEBUG_1) { BuildMsg("Adding PCH file to Sources List: %s.\n", FileDB->Name); } } if ((FileDB->FileFlags & (FILEDB_SOURCE | FILEDB_OBJECTS_LIST)) == FILEDB_SOURCE) { p = FileDB->Name; p1 = path; while (*p != '\0' && *p != '.') { *p1++ = *p++; } *p1 = '\0'; _strlwr(path); if (pdr->KernelTest != NULL && !strcmp(path, pdr->KernelTest)) { FileDB->FileFlags |= FILEDB_OBJECTS_LIST; } else if (pdr->UserAppls != NULL && (p = strstr(pdr->UserAppls, path)) && (p == pdr->UserAppls || p[-1] == '*' || p[-1] == ' ')) { FileDB->FileFlags |= FILEDB_OBJECTS_LIST; } else if (pdr->UserTests != NULL && (p = strstr(pdr->UserTests, path)) && (p == pdr->UserTests || p[-1] == '*' || p[-1] == ' ')) { FileDB->FileFlags |= FILEDB_OBJECTS_LIST; } if (FileDB->FileFlags & FILEDB_OBJECTS_LIST) { InsertSourceDB(&pds->psrSourcesList[0], FileDB, 0, 0); } } FileDBNext = &FileDB->Next; } return; } //+--------------------------------------------------------------------------- // // Function: ReadDirsFile // // Synopsis: Parse the DIRS file // // Arguments: [DirDB] -- Directory to look in // // Returns: TRUE if parsed // // Notes: The existence of a file named 'mydirs' or the name of the // target specific dirs will override the normal 'dirs' file. // //---------------------------------------------------------------------------- BOOL ReadDirsFile( PDIRREC DirDB ) { FILE *InFileHandle; LPSTR TextLine, pValue; LPSTR apszDirs[] = { "mydirs.", NULL, "dirs.", NULL }; CHAR TargetName[16]; strcpy(&TargetName[0], pszTargetDirs); strcat(&TargetName[0], "."); apszDirs[1] = &TargetName[0]; for (ppCurrentDirsFileName = apszDirs; *ppCurrentDirsFileName != NULL; ppCurrentDirsFileName++) { if (SetupReadFile(DirDB->Name, *ppCurrentDirsFileName, "#", &InFileHandle)) { break; } } if (*ppCurrentDirsFileName == NULL) { FreeMacros(); return(FALSE); } if (fFirstScan && (ppCurrentDirsFileName <= &apszDirs[1])) { BuildMsg("Using .\\%s instead of DIRS...\n", FormatPathName(DirDB->Name, *ppCurrentDirsFileName)); } if (DEBUG_1) { BuildMsg( " Scanning file %s\n", FormatPathName(DirDB->Name, *ppCurrentDirsFileName)); } assert(cMacro == 0); while ((TextLine = ReadLine(InFileHandle)) != NULL) { if ((pValue = SplitMacro(&TextLine)) != NULL) { SaveMacro(TextLine, pValue); FreeString(&TextLine, MT_DIRSTRING); } } CloseReadFile(NULL); if ((pValue = FindMacro("DIRS")) != NULL) { MarkDirNames(DirDB, pValue, TRUE); } if ((pValue = FindMacro("OPTIONAL_DIRS")) != NULL) { MarkDirNames(DirDB, pValue, BuildAllOptionalDirs); } if ((FindMacro("SYNCHRONIZE_DRAIN")) != NULL) { DirDB->DirFlags |= DIRDB_SYNCHRONIZE_DRAIN; } FreeMacros(); return( TRUE ); } // // Debugging and Utility Functions // VOID PrintDirSupData(DIRSUP *pds) { int i; if (pds->LocalIncludePath != NULL) { BuildMsgRaw(" LocalIncludePath: %s\n", pds->LocalIncludePath); } if (pds->TestType != NULL) { BuildMsgRaw(" TestType: %s\n", pds->TestType); } if (pds->PchIncludeDir != NULL) { BuildMsgRaw(" PchIncludeDir: %s\n", pds->PchIncludeDir); } if (pds->PchInclude != NULL) { BuildMsgRaw(" PchInclude: %s\n", pds->PchInclude); } if (pds->PchTargetDir != NULL) { BuildMsgRaw(" PchTargetDir: %s\n", pds->PchTargetDir); } if (pds->PchTarget != NULL) { BuildMsgRaw(" PchTarget: %s\n", pds->PchTarget); } if (pds->ConditionalIncludes != NULL) { BuildMsgRaw(" ConditionalIncludes: %s\n", pds->ConditionalIncludes); } for (i = 0; i < MAX_TARGET_MACHINES + 1; i++) { if (pds->SourcesVariables[i] != NULL) { BuildMsgRaw( " SourcesVariables[%d]: %s\n", i, pds->SourcesVariables[i]); } if (pds->psrSourcesList[i] != NULL) { BuildMsgRaw(" SourcesList[%d]:\n", i); PrintSourceDBList(pds->psrSourcesList[i], i - 1); } } } VOID FreeDirSupData(DIRSUP *pds) { int i; if (pds->LocalIncludePath != NULL) { FreeMem(&pds->LocalIncludePath, MT_DIRSTRING); } if (pds->TestType != NULL) { FreeMem(&pds->TestType, MT_DIRSTRING); } if (pds->PchInclude != NULL) { FreeMem(&pds->PchInclude, MT_DIRSTRING); } if (pds->PchIncludeDir != NULL) { FreeMem(&pds->PchIncludeDir, MT_DIRSTRING); } if (pds->PchTargetDir != NULL) { FreeMem(&pds->PchTargetDir, MT_DIRSTRING); } if (pds->PchTarget != NULL) { FreeMem(&pds->PchTarget, MT_DIRSTRING); } if (pds->ConditionalIncludes != NULL) { FreeMem(&pds->ConditionalIncludes, MT_DIRSTRING); } if (pds->PassZeroHdrDir != NULL) { FreeMem(&pds->PassZeroHdrDir, MT_DIRSTRING); } if (pds->PassZeroSrcDir1 != NULL) { FreeMem(&pds->PassZeroSrcDir1, MT_DIRSTRING); } if (pds->PassZeroSrcDir2 != NULL) { FreeMem(&pds->PassZeroSrcDir2, MT_DIRSTRING); } for (i = 0; i < MAX_TARGET_MACHINES + 1; i++) { if (pds->SourcesVariables[i] != NULL) { FreeMem(&pds->SourcesVariables[i], MT_DIRSTRING); } while (pds->psrSourcesList[i] != NULL) { FreeSourceDB(&pds->psrSourcesList[i]); } } } VOID FreeDirData(DIRREC *pdr) { if (pdr->TargetPath != NULL) { FreeMem(&pdr->TargetPath, MT_DIRSTRING); } if (pdr->TargetPathLib != NULL) { FreeMem(&pdr->TargetPathLib, MT_DIRSTRING); } if (pdr->TargetName != NULL) { FreeMem(&pdr->TargetName, MT_DIRSTRING); } if (pdr->TargetExt != NULL) { FreeMem(&pdr->TargetExt, MT_DIRSTRING); } if (pdr->KernelTest != NULL) { FreeMem(&pdr->KernelTest, MT_DIRSTRING); } if (pdr->UserAppls != NULL) { FreeMem(&pdr->UserAppls, MT_DIRSTRING); } if (pdr->UserTests != NULL) { FreeMem(&pdr->UserTests, MT_DIRSTRING); } if (pdr->NTTargetFile0 != NULL) { FreeMem(&pdr->NTTargetFile0, MT_DIRSTRING); } if (pdr->Pch != NULL) { FreeMem(&pdr->Pch, MT_DIRSTRING); } if (pdr->PchObj != NULL) { FreeMem(&pdr->PchObj, MT_DIRSTRING); } if (pdr->pds != NULL) { FreeDirSupData(pdr->pds); FreeMem(&pdr->pds, MT_DIRSUP); pdr->pds = NULL; } } //+--------------------------------------------------------------------------- // // Function: MarkDirNames // // Synopsis: Parses a DIRS= or OPTIONAL_DIRS line and marks the directories // appropriately. // // Arguments: [DirDB] -- Directory containing DIRS file // [TextLine] -- DIRS= or OPTIONAL_DIRS= line // [Required] -- Indicates if directories are optional or not. // //---------------------------------------------------------------------------- VOID MarkDirNames(PDIRREC DirDB, LPSTR TextLine, BOOL Required) { UINT i; LPSTR p, token; PFILEREC FileDB, *FileDBNext; char dirbuf[DB_MAX_PATH_LENGTH]; ULONG DirInclude; AssertPathString(TextLine); while (SplitToken(dirbuf, '*', &TextLine)) { // Assume all platforms are included for this dir. DirInclude = DIR_INCLUDE_ALL; for (p = dirbuf; *p != '\0'; p++) { if ( dirbuf != p && *p == '{' ) { // An explicit include path was listed. DirInclude = DIR_INCLUDE_NONE; *p = '\0'; token = strtok(p+1, ",}"); while (token) { if (!_stricmp(token, "X86") || !_stricmp(token, "I386") || !_stricmp(token, "386")) { DirInclude |= DIR_INCLUDE_X86; } else if (!_stricmp(token, "32") || !_stricmp(token, "Win32")) { DirInclude |= DIR_INCLUDE_WIN32; } else if (!_stricmp(token, "64") || !_stricmp(token, "Win64")) { DirInclude |= DIR_INCLUDE_WIN64; } else if (!_stricmp(token, "IA64")) { DirInclude |= DIR_INCLUDE_IA64; } else if (!_stricmp(token, "AMD64")) { DirInclude |= DIR_INCLUDE_AMD64; } else if (!_stricmp(token, "RISC")) { DirInclude |= DIR_INCLUDE_RISC; } token = strtok(NULL, ",}"); } break; } else { if (!iscsym(*p) && *p != '.' && *p != '-' ) { BuildError( "%s: ignoring bad subdirectory: %s\n", DirDB->Name, dirbuf); p = NULL; break; } } } if (!(DirInclude & TargetMachines[0]->DirIncludeMask)) { continue; } if (p != NULL) { if (!Required) { for (i = 0; i < CountOptionalDirs; i++) { if (!strcmp(dirbuf, OptionalDirs[i])) { OptionalDirsUsed[i] = TRUE; break; } } if (i >= CountOptionalDirs) { p = NULL; } } else { for (i = 0; i < CountExcludeDirs; i++) { if (!strcmp(dirbuf, ExcludeDirs[i])) { ExcludeDirsUsed[i] = TRUE; p = NULL; break; } } } } if (p != NULL) { if ((fQuicky || fSemiQuicky) && (!fQuickZero)) { FileDB = InsertFileDB( DirDB, dirbuf, 0, FILE_ATTRIBUTE_DIRECTORY, 0); if (FileDB != NULL) { FileDB->SubDirIndex = ++DirDB->CountSubDirs; } } else { FileDBNext = &DirDB->Files; while (FileDB = *FileDBNext) { if (FileDB->FileFlags & FILEDB_DIR) { if (!strcmp(dirbuf, FileDB->Name)) { FileDB->SubDirIndex = ++DirDB->CountSubDirs; break; } } FileDBNext = &FileDB->Next; } if (FileDB == NULL) { BuildError( "%s found in %s, is not a subdirectory of %s\n", dirbuf, FormatPathName(DirDB->Name, *ppCurrentDirsFileName), DirDB->Name); } } } } } VOID StartElapsedTime(VOID) { if (fPrintElapsed && StartTime == 0) { StartTime = GetTickCount(); } } VOID PrintElapsedTime(VOID) { DWORD ElapsedTime; DWORD ElapsedHours; DWORD ElapsedMinutes; DWORD ElapsedSeconds; DWORD ElapsedMilliseconds; if (fPrintElapsed) { ElapsedTime = GetTickCount() - StartTime; ElapsedHours = ElapsedTime/(1000 * 60 * 60); ElapsedTime = ElapsedTime % (1000 * 60 * 60); ElapsedMinutes = ElapsedTime/(1000 * 60); ElapsedTime = ElapsedTime % (1000 * 60); ElapsedSeconds = ElapsedTime/1000; ElapsedMilliseconds = ElapsedTime % 1000; BuildMsg( "Elapsed time [%d:%02d:%02d.%03d]\n", ElapsedHours, ElapsedMinutes, ElapsedSeconds, ElapsedMilliseconds); LogMsg( "Elapsed time [%d:%02d:%02d.%03d]%s\n", ElapsedHours, ElapsedMinutes, ElapsedSeconds, ElapsedMilliseconds, szAsterisks); } }