+++ /dev/null
-/*++\r
-\r
-Copyright (c) 2004, Intel Corporation \r
-All rights reserved. This program and the accompanying materials \r
-are licensed and made available under the terms and conditions of the BSD License \r
-which accompanies this distribution. The full text of the license may be found at \r
-http://opensource.org/licenses/bsd-license.php \r
- \r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
-\r
-Module Name:\r
-\r
- MakeDeps.c \r
-\r
-Abstract:\r
-\r
- Recursively scan source files to find include files and emit them to \r
- create dependency lists.\r
-\r
---*/\r
-\r
-#include <stdio.h>\r
-#include <string.h>\r
-#include <stdlib.h>\r
-#include <ctype.h>\r
-\r
-#include <Common/UefiBaseTypes.h>\r
-\r
-#include "EfiUtilityMsgs.h"\r
-#include "CommonLib.h"\r
-\r
-//\r
-// Structure to maintain a linked list of strings\r
-//\r
-typedef struct _STRING_LIST {\r
- struct _STRING_LIST *Next;\r
- char *Str;\r
-} STRING_LIST;\r
-\r
-#define UTILITY_NAME "MakeDeps"\r
-\r
-#define MAX_LINE_LEN 2048\r
-#define MAX_PATH 2048\r
-#define START_NEST_DEPTH 1\r
-#define MAX_NEST_DEPTH 1000 // just in case we get in an endless loop.\r
-//\r
-// Define the relative paths used by the special #include macros\r
-//\r
-#define PROTOCOL_DIR_PATH "Protocol/"\r
-#define GUID_DIR_PATH "Guid/"\r
-#define ARCH_PROTOCOL_DIR_PATH "ArchProtocol/"\r
-#define PPI_PROTOCOL_DIR_PATH "Ppi/"\r
-\r
-//\r
-// Use this structure to keep track of all the special #include forms\r
-//\r
-typedef struct {\r
- INT8 *IncludeMacroName;\r
- INT8 *PathName;\r
-} INCLUDE_MACRO_CONVERSION;\r
-\r
-//\r
-// This data is used to convert #include macros like:\r
-// #include EFI_PROTOCOL_DEFINITION(xxx)\r
-// into\r
-// #include Protocol/xxx/xxx.h\r
-//\r
-static const INCLUDE_MACRO_CONVERSION mMacroConversion[] = {\r
- "EFI_PROTOCOL_DEFINITION",\r
- PROTOCOL_DIR_PATH,\r
- "EFI_GUID_DEFINITION",\r
- GUID_DIR_PATH,\r
- "EFI_ARCH_PROTOCOL_DEFINITION",\r
- ARCH_PROTOCOL_DIR_PATH,\r
- "EFI_PROTOCOL_PRODUCER",\r
- PROTOCOL_DIR_PATH,\r
- "EFI_PROTOCOL_CONSUMER",\r
- PROTOCOL_DIR_PATH,\r
- "EFI_PROTOCOL_DEPENDENCY",\r
- PROTOCOL_DIR_PATH,\r
- "EFI_ARCH_PROTOCOL_PRODUCER",\r
- ARCH_PROTOCOL_DIR_PATH,\r
- "EFI_ARCH_PROTOCOL_CONSUMER",\r
- ARCH_PROTOCOL_DIR_PATH,\r
- "EFI_ARCH_PROTOCOL_DEPENDENCY",\r
- ARCH_PROTOCOL_DIR_PATH,\r
- "EFI_PPI_DEFINITION",\r
- PPI_PROTOCOL_DIR_PATH,\r
- "EFI_PPI_PRODUCER",\r
- PPI_PROTOCOL_DIR_PATH,\r
- "EFI_PPI_CONSUMER",\r
- PPI_PROTOCOL_DIR_PATH,\r
- "EFI_PPI_DEPENDENCY",\r
- PPI_PROTOCOL_DIR_PATH,\r
- NULL,\r
- NULL\r
-};\r
-\r
-typedef struct _SYMBOL {\r
- struct _SYMBOL *Next;\r
- INT8 *Name;\r
- INT8 *Value;\r
-} SYMBOL;\r
-\r
-//\r
-// Here's all our globals. We need a linked list of include paths, a linked\r
-// list of source files, a linked list of subdirectories (appended to each\r
-// include path when searching), and flags to keep track of command-line options.\r
-//\r
-static struct {\r
- STRING_LIST *IncludePaths; // all include paths to search\r
- STRING_LIST *SourceFiles; // all source files to parse\r
- STRING_LIST *SubDirs; // appended to each include path when searching\r
- SYMBOL *SymbolTable; // for replacement strings\r
- FILE *OutFptr; // output dependencies to this file\r
- BOOLEAN Verbose; // for more detailed output\r
- BOOLEAN IgnoreNotFound; // no warnings if files not found\r
- BOOLEAN QuietMode; // -q - don't print missing file warnings\r
- BOOLEAN NoSystem; // don't process #include <system> files\r
- BOOLEAN NeverFail; // always return success\r
- BOOLEAN NoDupes; // to not list duplicate dependency files (for timing purposes)\r
- BOOLEAN UseSumDeps; // use summary dependency files if found\r
- INT8 TargetFileName[MAX_PATH]; // target object filename\r
- INT8 SumDepsPath[MAX_PATH]; // path to summary files\r
- INT8 *OutFileName; // -o option\r
-} mGlobals;\r
-\r
-static\r
-STATUS\r
-ProcessFile (\r
- INT8 *TargetFileName,\r
- INT8 *FileName,\r
- UINT32 NestDepth,\r
- STRING_LIST *ProcessedFiles\r
- );\r
-\r
-static\r
-FILE *\r
-FindFile (\r
- INT8 *FileName,\r
- UINT32 FileNameLen\r
- );\r
-\r
-static\r
-void\r
-PrintDependency (\r
- INT8 *Target,\r
- INT8 *DependentFile\r
- );\r
-\r
-static\r
-void\r
-ReplaceSymbols (\r
- INT8 *Str,\r
- UINT32 StrSize\r
- );\r
-\r
-static\r
-STATUS\r
-ProcessArgs (\r
- int Argc,\r
- char *Argv[]\r
- );\r
-\r
-static\r
-void\r
-Usage (\r
- VOID\r
- );\r
-\r
-static\r
-void\r
-FreeLists (\r
- VOID\r
- );\r
-\r
-int\r
-main (\r
- int Argc,\r
- char *Argv[]\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Call the routine to parse the command-line options, then process each file\r
- to build dependencies.\r
- \r
-Arguments:\r
-\r
- Argc - Standard C main() argc.\r
- Argv - Standard C main() argv.\r
-\r
-Returns:\r
-\r
- 0 if successful\r
- nonzero otherwise\r
- \r
---*/\r
-{\r
- STRING_LIST *File;\r
- STRING_LIST ProcessedFiles;\r
- STRING_LIST *TempList;\r
- STATUS Status;\r
- INT8 *Cptr;\r
- INT8 TargetFileName[MAX_PATH];\r
-\r
- SetUtilityName (UTILITY_NAME);\r
- //\r
- // Process the command-line arguments\r
- //\r
- Status = ProcessArgs (Argc, Argv);\r
- if (Status != STATUS_SUCCESS) {\r
- return STATUS_ERROR;\r
- }\r
- //\r
- // Go through the list of source files and process each.\r
- //\r
- memset (&ProcessedFiles, 0, sizeof (STRING_LIST));\r
- File = mGlobals.SourceFiles;\r
- while (File != NULL) {\r
- //\r
- // Clear out our list of processed files\r
- //\r
- TempList = ProcessedFiles.Next;\r
- while (ProcessedFiles.Next != NULL) {\r
- TempList = ProcessedFiles.Next->Next;\r
- free (ProcessedFiles.Next->Str);\r
- free (ProcessedFiles.Next);\r
- ProcessedFiles.Next = TempList;\r
- }\r
- //\r
- // Replace filename extension with ".obj" if they did not\r
- // specifically specify the target file\r
- //\r
- if (mGlobals.TargetFileName[0] == 0) {\r
- strcpy (TargetFileName, File->Str);\r
- //\r
- // Find the .extension\r
- //\r
- for (Cptr = TargetFileName + strlen (TargetFileName) - 1;\r
- (*Cptr != '\\' && *Cptr != '/') && (Cptr > TargetFileName) && (*Cptr != '.');\r
- Cptr--\r
- )\r
- ;\r
- if (Cptr == TargetFileName) {\r
- Error (NULL, 0, 0, File->Str, "could not locate extension in filename");\r
- goto Finish;\r
- }\r
- //\r
- // Tack on the ".obj"\r
- //\r
- strcpy (Cptr, ".obj");\r
- } else {\r
- //\r
- // Copy the target filename they specified\r
- //\r
- strcpy (TargetFileName, mGlobals.TargetFileName);\r
- }\r
-\r
- Status = ProcessFile (TargetFileName, File->Str, START_NEST_DEPTH, &ProcessedFiles);\r
- if (Status != STATUS_SUCCESS) {\r
- goto Finish;\r
- }\r
-\r
- File = File->Next;\r
- }\r
-\r
-Finish:\r
- //\r
- // Free up memory\r
- //\r
- FreeLists ();\r
- //\r
- // Free up our processed files list\r
- //\r
- TempList = ProcessedFiles.Next;\r
- while (ProcessedFiles.Next != NULL) {\r
- TempList = ProcessedFiles.Next->Next;\r
- free (ProcessedFiles.Next->Str);\r
- free (ProcessedFiles.Next);\r
- ProcessedFiles.Next = TempList;\r
- }\r
- //\r
- // Close our output file\r
- //\r
- if ((mGlobals.OutFptr != stdout) && (mGlobals.OutFptr != NULL)) {\r
- fprintf(mGlobals.OutFptr, "\t\n"); // file ending flag\r
- fclose (mGlobals.OutFptr);\r
- }\r
-\r
- if (mGlobals.NeverFail) {\r
- return STATUS_SUCCESS;\r
- }\r
- //\r
- // If any errors, then delete our output so that it will get created\r
- // again on a rebuild.\r
- //\r
- if ((GetUtilityStatus () == STATUS_ERROR) && (mGlobals.OutFileName != NULL)) {\r
- remove (mGlobals.OutFileName);\r
- }\r
-\r
- return GetUtilityStatus ();\r
-}\r
-\r
-static\r
-STATUS\r
-ProcessFile (\r
- INT8 *TargetFileName,\r
- INT8 *FileName,\r
- UINT32 NestDepth,\r
- STRING_LIST *ProcessedFiles\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Given a source file name, open the file and parse all #include lines.\r
- \r
-Arguments:\r
-\r
- TargetFileName - name of the usually .obj target\r
- FileName - name of the file to process\r
- NestDepth - how deep we're nested in includes\r
- ProcessedFiles - list of processed files.\r
-\r
-Returns:\r
-\r
- standard status.\r
- \r
---*/\r
-{\r
- FILE *Fptr;\r
- INT8 Line[MAX_LINE_LEN];\r
- INT8 *Cptr;\r
- INT8 *EndPtr;\r
- INT8 *SaveCptr;\r
- INT8 EndChar;\r
- INT8 FileNameCopy[MAX_PATH];\r
- INT8 MacroIncludeFileName[MAX_LINE_LEN];\r
- INT8 SumDepsFile[MAX_PATH];\r
- STATUS Status;\r
- UINT32 Index;\r
- UINT32 LineNum;\r
- STRING_LIST *ListPtr;\r
-\r
- Status = STATUS_SUCCESS;\r
- Fptr = NULL;\r
- //\r
- // Print the file being processed. Indent so you can tell the include nesting\r
- // depth.\r
- //\r
- if (mGlobals.Verbose) {\r
- fprintf (stdout, "%*cProcessing file '%s'\n", NestDepth * 2, ' ', FileName);\r
- }\r
- //\r
- // If we're using summary dependency files, and a matching .dep file is\r
- // found for this file, then just emit the summary dependency file as\r
- // a dependency and return.\r
- //\r
- if (mGlobals.UseSumDeps) {\r
- strcpy (SumDepsFile, mGlobals.SumDepsPath);\r
- strcat (SumDepsFile, FileName);\r
- for (Cptr = SumDepsFile + strlen (SumDepsFile) - 1;\r
- (*Cptr != '\\' && *Cptr != '/') && (Cptr > SumDepsFile) && (*Cptr != '.');\r
- Cptr--\r
- )\r
- ;\r
- if (*Cptr == '.') {\r
- strcpy (Cptr, ".dep");\r
- } else {\r
- strcat (SumDepsFile, ".dep");\r
- }\r
- //\r
- // See if the summary dep file exists. Could use _stat() function, but\r
- // it's less portable.\r
- //\r
- if ((Fptr = fopen (SumDepsFile, "r")) != NULL) {\r
- PrintDependency (TargetFileName, SumDepsFile);\r
- return STATUS_SUCCESS;\r
- }\r
- }\r
- //\r
- // If we're not doing duplicates, and we've already seen this filename,\r
- // then return\r
- //\r
- if (mGlobals.NoDupes) {\r
- for (ListPtr = ProcessedFiles->Next; ListPtr != NULL; ListPtr = ListPtr->Next) {\r
- if (stricmp (FileName, ListPtr->Str) == 0) {\r
- break;\r
- }\r
- }\r
- //\r
- // If we found a match, we're done. If we didn't, create a new element\r
- // and add it to the list.\r
- //\r
- if (ListPtr != NULL) {\r
- //\r
- // Print a message if verbose mode\r
- //\r
- if (mGlobals.Verbose) {\r
- DebugMsg (NULL, 0, 0, FileName, "duplicate include -- not processed again");\r
- }\r
-\r
- return STATUS_SUCCESS;\r
- }\r
-\r
- ListPtr = malloc (sizeof (STRING_LIST));\r
- ListPtr->Str = malloc (strlen (FileName) + 1);\r
- strcpy (ListPtr->Str, FileName);\r
- ListPtr->Next = ProcessedFiles->Next;\r
- ProcessedFiles->Next = ListPtr;\r
- }\r
-\r
- //\r
- // Make sure we didn't exceed our maximum nesting depth\r
- //\r
- if (NestDepth > MAX_NEST_DEPTH) {\r
- Error (NULL, 0, 0, FileName, "max nesting depth exceeded on file");\r
- goto Finish;\r
- }\r
- //\r
- // Make a local copy of the filename. Then we can manipulate it\r
- // if we have to.\r
- //\r
- strcpy (FileNameCopy, FileName);\r
- //\r
- // Try to open the file locally\r
- //\r
- if ((Fptr = fopen (FileNameCopy, "r")) == NULL) {\r
- //\r
- // Try to find it among the paths.\r
- //\r
- Fptr = FindFile (FileNameCopy, sizeof (FileNameCopy));\r
- if (Fptr == NULL) {\r
- //\r
- // If this is not the top-level file, and the command-line argument\r
- // said to ignore missing files, then return ok\r
- //\r
- if (NestDepth != START_NEST_DEPTH) {\r
- if (mGlobals.IgnoreNotFound) {\r
- if (!mGlobals.QuietMode) {\r
- DebugMsg (NULL, 0, 0, FileNameCopy, "could not find file");\r
- }\r
-\r
- return STATUS_SUCCESS;\r
- } else {\r
- Error (NULL, 0, 0, FileNameCopy, "could not find file");\r
- return STATUS_ERROR;\r
- }\r
- } else {\r
- //\r
- // Top-level (first) file. Emit an error.\r
- //\r
- Error (NULL, 0, 0, FileNameCopy, "could not find file");\r
- return STATUS_ERROR;\r
- }\r
- }\r
- }\r
- //\r
- // Print the dependency, with string substitution\r
- //\r
- PrintDependency (TargetFileName, FileNameCopy);\r
-\r
- //\r
- // Now read in lines and find all #include lines. Allow them to indent, and\r
- // to put spaces between the # and include.\r
- //\r
- LineNum = 0;\r
- while ((fgets (Line, sizeof (Line), Fptr) != NULL) && (Status == STATUS_SUCCESS)) {\r
- LineNum++;\r
- Cptr = Line;\r
- //\r
- // Skip preceeding spaces on the line\r
- //\r
- while (*Cptr && (isspace (*Cptr))) {\r
- Cptr++;\r
- }\r
- //\r
- // Check for # character\r
- //\r
- if (*Cptr == '#') {\r
- Cptr++;\r
- //\r
- // Check for "include"\r
- //\r
- while (*Cptr && (isspace (*Cptr))) {\r
- Cptr++;\r
- }\r
-\r
- if (strncmp (Cptr, "include", 7) == 0) {\r
- //\r
- // Skip over "include" and move on to filename as "file" or <file>\r
- //\r
- Cptr += 7;\r
- while (*Cptr && (isspace (*Cptr))) {\r
- Cptr++;\r
- }\r
-\r
- if (*Cptr == '<') {\r
- EndChar = '>';\r
- } else if (*Cptr == '"') {\r
- EndChar = '"';\r
- } else {\r
- //\r
- // Handle special #include MACRO_NAME(file)\r
- // Set EndChar to null so we fall through on processing below.\r
- //\r
- EndChar = 0;\r
- //\r
- // Look for all the special include macros and convert accordingly.\r
- //\r
- for (Index = 0; mMacroConversion[Index].IncludeMacroName != NULL; Index++) {\r
- //\r
- // Save the start of the string in case some macros are substrings\r
- // of others.\r
- //\r
- SaveCptr = Cptr;\r
- if (strncmp (\r
- Cptr,\r
- mMacroConversion[Index].IncludeMacroName,\r
- strlen (mMacroConversion[Index].IncludeMacroName)\r
- ) == 0) {\r
- //\r
- // Skip over the macro name\r
- //\r
- Cptr += strlen (mMacroConversion[Index].IncludeMacroName);\r
- //\r
- // Skip over open parenthesis, blank spaces, then find closing\r
- // parenthesis or blank space\r
- //\r
- while (*Cptr && (isspace (*Cptr))) {\r
- Cptr++;\r
- }\r
-\r
- if (*Cptr == '(') {\r
- Cptr++;\r
- while (*Cptr && (isspace (*Cptr))) {\r
- Cptr++;\r
- }\r
-\r
- EndPtr = Cptr;\r
- while (*EndPtr && !isspace (*EndPtr) && (*EndPtr != ')')) {\r
- EndPtr++;\r
- }\r
-\r
- *EndPtr = 0;\r
- //\r
- // Create the path\r
- //\r
- strcpy (MacroIncludeFileName, mMacroConversion[Index].PathName);\r
- strcat (MacroIncludeFileName, Cptr);\r
- strcat (MacroIncludeFileName, "/");\r
- strcat (MacroIncludeFileName, Cptr);\r
- strcat (MacroIncludeFileName, ".h");\r
- //\r
- // Process immediately, then break out of the outside FOR loop.\r
- //\r
- Status = ProcessFile (TargetFileName, MacroIncludeFileName, NestDepth + 1, ProcessedFiles);\r
- break;\r
- }\r
- }\r
- //\r
- // Restore the start\r
- //\r
- Cptr = SaveCptr;\r
- }\r
- //\r
- // Don't recognize the include line? Ignore it. We assume that the\r
- // file compiles anyway.\r
- //\r
- if (mMacroConversion[Index].IncludeMacroName == NULL) {\r
- //\r
- // Warning (FileNameCopy, LineNum, 0, "could not parse line", NULL);\r
- // Status = STATUS_WARNING;\r
- //\r
- }\r
- }\r
- //\r
- // Process "normal" includes. If the endchar is 0, then the\r
- // file has already been processed. Otherwise look for the\r
- // endchar > or ", and process the include file.\r
- //\r
- if (EndChar != 0) {\r
- Cptr++;\r
- EndPtr = Cptr;\r
- while (*EndPtr && (*EndPtr != EndChar)) {\r
- EndPtr++;\r
- }\r
-\r
- if (*EndPtr == EndChar) {\r
- //\r
- // If we're processing it, do it\r
- //\r
- if ((EndChar != '>') || (!mGlobals.NoSystem)) {\r
- //\r
- // Null terminate the filename and try to process it.\r
- //\r
- *EndPtr = 0;\r
- Status = ProcessFile (TargetFileName, Cptr, NestDepth + 1, ProcessedFiles);\r
- }\r
- } else {\r
- Warning (FileNameCopy, LineNum, 0, "malformed include", "missing closing %c", EndChar);\r
- Status = STATUS_WARNING;\r
- goto Finish;\r
- }\r
- }\r
- }\r
- }\r
- }\r
-\r
-Finish:\r
- //\r
- // Close open files and return status\r
- //\r
- if (Fptr != NULL) {\r
- fclose (Fptr);\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-static\r
-void\r
-PrintDependency (\r
- INT8 *TargetFileName,\r
- INT8 *DependentFile\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Given a target (.obj) file name, and a dependent file name, do any string\r
- substitutions (per the command line options) on the file names, then\r
- print the dependency line of form:\r
- \r
- TargetFileName : DependentFile\r
- \r
-Arguments:\r
-\r
- TargetFileName - build target file name\r
- DependentFile - file on which TargetFileName depends\r
-\r
-Returns:\r
-\r
- None\r
- \r
---*/\r
-{\r
- INT8 Str[MAX_PATH];\r
-\r
- //\r
- // Go through the symbols and do replacements\r
- //\r
- strcpy (Str, DependentFile);\r
- ReplaceSymbols (Str, sizeof (Str));\r
- fprintf (mGlobals.OutFptr, "%s\n", Str);\r
-}\r
-\r
-static\r
-void\r
-ReplaceSymbols (\r
- INT8 *Str,\r
- UINT32 StrSize\r
- )\r
-{\r
- SYMBOL *Sym;\r
- INT8 StrCopy[MAX_LINE_LEN];\r
- INT8 *From;\r
- INT8 *To;\r
- BOOLEAN Replaced;\r
-\r
- //\r
- // Go through the entire string to look for replacement strings at\r
- // every position.\r
- //\r
- From = Str;\r
- To = StrCopy;\r
- while (*From) {\r
- //\r
- // Copy the character\r
- //\r
- *To = *From;\r
- Replaced = FALSE;\r
- //\r
- // Go through each symbol and try to find a string substitution\r
- //\r
- Sym = mGlobals.SymbolTable;\r
- while (Sym != NULL) {\r
- if (strnicmp (From, Sym->Value, strlen (Sym->Value)) == 0) {\r
- //\r
- // Replace the string, then advance the pointers past the\r
- // replaced strings\r
- //\r
- strcpy (To, Sym->Name);\r
- To += strlen (Sym->Name);\r
- From += strlen (Sym->Value);\r
- Replaced = TRUE;\r
- //\r
- // Break from the while()\r
- //\r
- break;\r
- } else {\r
- Sym = Sym->Next;\r
- }\r
- }\r
-\r
- if (!Replaced) {\r
- From++;\r
- To++;\r
- }\r
- }\r
- //\r
- // Null terminate, and return it\r
- //\r
- *To = 0;\r
- if (strlen (StrCopy) < StrSize) {\r
- strcpy (Str, StrCopy);\r
- }\r
-}\r
-//\r
-// Given a filename, try to find it along the include paths.\r
-//\r
-static\r
-FILE *\r
-FindFile (\r
- INT8 *FileName,\r
- UINT32 FileNameLen\r
- )\r
-{\r
- FILE *Fptr;\r
- STRING_LIST *List;\r
- STRING_LIST *SubDir;\r
- INT8 FullFileName[MAX_PATH * 2];\r
-\r
- //\r
- // Traverse the list of paths and try to find the file\r
- //\r
- List = mGlobals.IncludePaths;\r
- while (List != NULL) {\r
- //\r
- // Put the path and filename together\r
- //\r
- if (strlen (List->Str) + strlen (FileName) + 1 > sizeof (FullFileName)) {\r
- Error (\r
- __FILE__,\r
- __LINE__,\r
- 0,\r
- "application error",\r
- "cannot concatenate '%s' + '%s'",\r
- List->Str,\r
- FileName\r
- );\r
- return NULL;\r
- }\r
- //\r
- // Append the filename to this include path and try to open the file.\r
- //\r
- strcpy (FullFileName, List->Str);\r
- strcat (FullFileName, FileName);\r
- if ((Fptr = fopen (FullFileName, "r")) != NULL) {\r
- //\r
- // Return the file name\r
- //\r
- if (FileNameLen <= strlen (FullFileName)) {\r
- Error (__FILE__, __LINE__, 0, "application error", "internal path name of insufficient length");\r
- //\r
- // fprintf (stdout, "File length > %d: %s\n", FileNameLen, FullFileName);\r
- //\r
- return NULL;\r
- }\r
-\r
- strcpy (FileName, FullFileName);\r
- return Fptr;\r
- }\r
- //\r
- // Didn't find it there. Now try this directory with every subdirectory\r
- // the user specified on the command line\r
- //\r
- for (SubDir = mGlobals.SubDirs; SubDir != NULL; SubDir = SubDir->Next) {\r
- strcpy (FullFileName, List->Str);\r
- strcat (FullFileName, SubDir->Str);\r
- strcat (FullFileName, FileName);\r
- if ((Fptr = fopen (FullFileName, "r")) != NULL) {\r
- //\r
- // Return the file name\r
- //\r
- if (FileNameLen <= strlen (FullFileName)) {\r
- Error (__FILE__, __LINE__, 0, "application error", "internal path name of insufficient length");\r
- return NULL;\r
- }\r
-\r
- strcpy (FileName, FullFileName);\r
- return Fptr;\r
- }\r
- }\r
-\r
- List = List->Next;\r
- }\r
- //\r
- // Not found\r
- //\r
- return NULL;\r
-}\r
-//\r
-// Process the command-line arguments\r
-//\r
-static\r
-STATUS\r
-ProcessArgs (\r
- int Argc,\r
- char *Argv[]\r
- )\r
-{\r
- STRING_LIST *NewList;\r
- STRING_LIST *LastIncludePath;\r
- STRING_LIST *LastSourceFile;\r
- SYMBOL *Symbol;\r
- int Index;\r
- //\r
- // Clear our globals\r
- //\r
- memset ((char *) &mGlobals, 0, sizeof (mGlobals));\r
- mGlobals.NoDupes = TRUE;\r
- //\r
- // Skip program name\r
- //\r
- Argc--;\r
- Argv++;\r
- //\r
- // Initialize locals\r
- //\r
- LastIncludePath = NULL;\r
- LastSourceFile = NULL;\r
- //\r
- // Process until no more args\r
- //\r
- while (Argc) {\r
- //\r
- // -i path add include search path\r
- //\r
- if (stricmp (Argv[0], "-i") == 0) {\r
- //\r
- // check for one more arg\r
- //\r
- if (Argc > 1) {\r
- //\r
- // Allocate memory for a new list element, fill it in, and\r
- // add it to our list of include paths. Always make sure it\r
- // has a "\" on the end of it.\r
- //\r
- NewList = malloc (sizeof (STRING_LIST));\r
- if (NewList == NULL) {\r
- Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
- return STATUS_ERROR;\r
- }\r
-\r
- NewList->Next = NULL;\r
- NewList->Str = malloc (strlen (Argv[1]) + 2);\r
- if (NewList->Str == NULL) {\r
- free (NewList);\r
- Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
- return STATUS_ERROR;\r
- }\r
-\r
- strcpy (NewList->Str, Argv[1]);\r
- if (NewList->Str[strlen (NewList->Str) - 1] != '\\' && NewList->Str[strlen (NewList->Str) - 1] != '/') {\r
- strcat (NewList->Str, "/");\r
- }\r
- //\r
- // Add it to the end of the our list of include paths\r
- //\r
- if (mGlobals.IncludePaths == NULL) {\r
- mGlobals.IncludePaths = NewList;\r
- } else {\r
- LastIncludePath->Next = NewList;\r
- }\r
-\r
- LastIncludePath = NewList;\r
- //\r
- // fprintf (stdout, "Added path: %s\n", NewList->Str);\r
- //\r
- } else {\r
- Error (NULL, 0, 0, Argv[0], "option requires an include path");\r
- Usage ();\r
- return STATUS_ERROR;\r
- }\r
-\r
- Argc--;\r
- Argv++;\r
- } else if (stricmp (Argv[0], "-f") == 0) {\r
- //\r
- // Check for one more arg\r
- //\r
- if (Argc > 1) {\r
- //\r
- // Allocate memory for a new list element, fill it in, and\r
- // add it to our list of source files.\r
- //\r
- NewList = malloc (sizeof (STRING_LIST));\r
- if (NewList == NULL) {\r
- Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
- return STATUS_ERROR;\r
- }\r
-\r
- NewList->Next = NULL;\r
- //\r
- // Allocate space to replace ".c" with ".obj", plus null termination\r
- //\r
- NewList->Str = malloc (strlen (Argv[1]) + 5);\r
- if (NewList->Str == NULL) {\r
- free (NewList);\r
- Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
- return STATUS_ERROR;\r
- }\r
-\r
- strcpy (NewList->Str, Argv[1]);\r
- if (mGlobals.SourceFiles == NULL) {\r
- mGlobals.SourceFiles = NewList;\r
- } else {\r
- LastSourceFile->Next = NewList;\r
- }\r
-\r
- LastSourceFile = NewList;\r
- } else {\r
- Error (NULL, 0, 0, Argv[0], "option requires a file name");\r
- Usage ();\r
- return STATUS_ERROR;\r
- }\r
- //\r
- // The C compiler first looks for #include files in the directory where\r
- // the source file came from. Add the file's source directory to the\r
- // list of include paths.\r
- //\r
- NewList = malloc (sizeof (STRING_LIST));\r
- if (NewList == NULL) {\r
- Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
- return STATUS_ERROR;\r
- }\r
-\r
- NewList->Next = NULL;\r
- NewList->Str = malloc (strlen (Argv[1]) + 3);\r
- if (NewList->Str == NULL) {\r
- free (NewList);\r
- Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
- return STATUS_ERROR;\r
- }\r
-\r
- strcpy (NewList->Str, Argv[1]);\r
- //\r
- // Back up in the source file name to the last backslash and terminate after it.\r
- //\r
- for (Index = strlen (NewList->Str) - 1; (Index > 0) && (NewList->Str[Index] != '\\' && NewList->Str[Index] != '/'); Index--)\r
- ;\r
- if (Index < 0) {\r
- strcpy (NewList->Str, "./");\r
- } else {\r
- NewList->Str[Index + 1] = 0;\r
- }\r
- //\r
- // Add it to the end of the our list of include paths\r
- //\r
- if (mGlobals.IncludePaths == NULL) {\r
- mGlobals.IncludePaths = NewList;\r
- } else {\r
- LastIncludePath->Next = NewList;\r
- }\r
-\r
- if (mGlobals.Verbose) {\r
- fprintf (stdout, "Adding include path: %s\n", NewList->Str);\r
- }\r
-\r
- LastIncludePath = NewList;\r
- Argc--;\r
- Argv++;\r
- } else if (stricmp (Argv[0], "-s") == 0) {\r
- //\r
- // -s subdir add subdirectory subdir to list of subdirecties to scan.\r
- // Check for one more arg first.\r
- //\r
- if (Argc > 1) {\r
- //\r
- // Allocate memory for a new list element, fill it in, and\r
- // add it to our list of subdirectory include paths. Always\r
- // make sure it has a "\" on the end of it.\r
- //\r
- NewList = malloc (sizeof (STRING_LIST));\r
- if (NewList == NULL) {\r
- Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
- return STATUS_ERROR;\r
- }\r
-\r
- NewList->Str = malloc (strlen (Argv[1]) + 2);\r
- if (NewList->Str == NULL) {\r
- free (NewList);\r
- Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
- return STATUS_ERROR;\r
- }\r
-\r
- strcpy (NewList->Str, Argv[1]);\r
- if (NewList->Str[strlen (NewList->Str) - 1] != '\\' && NewList->Str[strlen (NewList->Str) - 1] != '/') {\r
- strcat (NewList->Str, "/");\r
- }\r
-\r
- NewList->Next = mGlobals.SubDirs;\r
- mGlobals.SubDirs = NewList;\r
- } else {\r
- Error (NULL, 0, 0, Argv[0], "option requires a subdirectory name");\r
- Usage ();\r
- return STATUS_ERROR;\r
- }\r
-\r
- Argc--;\r
- Argv++;\r
- } else if (stricmp (Argv[0], "-sub") == 0) {\r
- //\r
- // -sub symname symvalue to do string substitution in the output\r
- //\r
- if (Argc > 2) {\r
- //\r
- // Allocate memory for the symbol object\r
- //\r
- Symbol = malloc (sizeof (SYMBOL));\r
- if (Symbol == NULL) {\r
- Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
- return STATUS_ERROR;\r
- }\r
- //\r
- // Allocate memory for the symbol name and value, then save copies\r
- //\r
- Symbol->Name = malloc (strlen (Argv[1]) + 1);\r
- if (Symbol->Name == NULL) {\r
- free (Symbol);\r
- Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
- return STATUS_ERROR;\r
- }\r
-\r
- strcpy (Symbol->Name, Argv[1]);\r
- Symbol->Value = malloc (strlen (Argv[2]) + 1);\r
- if (Symbol->Value == NULL) {\r
- free (Symbol->Name);\r
- free (Symbol);\r
- Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
- return STATUS_ERROR;\r
- }\r
-\r
- strcpy (Symbol->Value, Argv[2]);\r
- //\r
- // Add it to the list\r
- //\r
- Symbol->Next = mGlobals.SymbolTable;\r
- mGlobals.SymbolTable = Symbol;\r
- } else {\r
- Error (NULL, 0, 0, Argv[0], "option requires a symbol name and value");\r
- Usage ();\r
- return STATUS_ERROR;\r
- }\r
- //\r
- // Skip over args\r
- //\r
- Argc -= 2;\r
- Argv += 2;\r
- } else if (stricmp (Argv[0], "-nosystem") == 0) {\r
- mGlobals.NoSystem = TRUE;\r
- } else if (stricmp (Argv[0], "-nodupes") == 0) {\r
- mGlobals.NoDupes = TRUE;\r
- } else if (stricmp (Argv[0], "-nodups") == 0) {\r
- mGlobals.NoDupes = TRUE;\r
- } else if (stricmp (Argv[0], "-target") == 0) {\r
- //\r
- // -target TargetFileName - Target object file (only one allowed right\r
- // now) is TargetFileName rather than SourceFile.obj\r
- //\r
- if (Argc > 1) {\r
- strcpy (mGlobals.TargetFileName, Argv[1]);\r
- } else {\r
- Error (NULL, 0, 0, Argv[0], "option requires a target file name");\r
- Usage ();\r
- return STATUS_ERROR;\r
- }\r
-\r
- Argc--;\r
- Argv++;\r
- } else if (stricmp (Argv[0], "-usesumdeps") == 0) {\r
- //\r
- // -usesumdeps Path - if we find an included file xxx.h, and file\r
- // Path/xxx.dep exists, list Path/xxx.dep as a dependency rather than\r
- // xxx.h and don't parse xxx.h. This allows you to create a dependency\r
- // file for a commonly included file, and have its dependency file updated\r
- // only if its included files are updated. Then anyone else including this\r
- // common include file can simply have a dependency on that file's .dep file\r
- // rather than on all the files included by it. Confusing enough?\r
- //\r
- mGlobals.UseSumDeps = 1;\r
- if (Argc > 1) {\r
- strcpy (mGlobals.SumDepsPath, Argv[1]);\r
- //\r
- // Add slash on end if not there\r
- //\r
- if (mGlobals.SumDepsPath[strlen (mGlobals.SumDepsPath) - 1] != '\\' && mGlobals.SumDepsPath[strlen (mGlobals.SumDepsPath) - 1] != '/') {\r
- strcat (mGlobals.SumDepsPath, "/");\r
- }\r
- } else {\r
- Error (NULL, 0, 0, Argv[0], "option requires path to summary dependency files");\r
- Usage ();\r
- return STATUS_ERROR;\r
- }\r
-\r
- Argc--;\r
- Argv++;\r
-\r
- } else if (stricmp (Argv[0], "-o") == 0) {\r
- //\r
- // -o OutputFileName - specify an output filename for dependency list\r
- // check for one more arg\r
- //\r
- if (Argc > 1) {\r
- //\r
- // Try to open the file\r
- //\r
- if ((mGlobals.OutFptr = fopen (Argv[1], "w")) == NULL) {\r
- Error (NULL, 0, 0, Argv[1], "could not open file for writing");\r
- return STATUS_ERROR;\r
- }\r
-\r
- mGlobals.OutFileName = Argv[1];\r
- } else {\r
- Error (NULL, 0, 0, Argv[0], "option requires output file name");\r
- Usage ();\r
- return STATUS_ERROR;\r
- }\r
-\r
- Argc--;\r
- Argv++;\r
- } else if (stricmp (Argv[0], "-v") == 0) {\r
- mGlobals.Verbose = TRUE;\r
- } else if (stricmp (Argv[0], "-neverfail") == 0) {\r
- mGlobals.NeverFail = TRUE;\r
- } else if (stricmp (Argv[0], "-q") == 0) {\r
- mGlobals.QuietMode = TRUE;\r
- } else if (stricmp (Argv[0], "-ignorenotfound") == 0) {\r
- mGlobals.IgnoreNotFound = TRUE;\r
- } else if ((stricmp (Argv[0], "-h") == 0) || (strcmp (Argv[0], "-?") == 0)) {\r
- Usage ();\r
- return STATUS_ERROR;\r
- } else {\r
- Error (NULL, 0, 0, Argv[0], "unrecognized option");\r
- Usage ();\r
- return STATUS_ERROR;\r
- }\r
-\r
- Argc--;\r
- Argv++;\r
- }\r
- //\r
- // Had to specify at least one source file\r
- //\r
- if (mGlobals.SourceFiles == NULL) {\r
- Error (NULL, 0, 0, "must specify one source file name", NULL);\r
- Usage ();\r
- return STATUS_ERROR;\r
- }\r
- //\r
- // Assume output to stdout if not specified\r
- //\r
- if (mGlobals.OutFptr == NULL) {\r
- mGlobals.OutFptr = stdout;\r
- }\r
-\r
- return STATUS_SUCCESS;\r
-}\r
-//\r
-// Free the global string lists we allocated memory for\r
-//\r
-static\r
-void\r
-FreeLists (\r
- VOID\r
- )\r
-{\r
- STRING_LIST *Temp;\r
- SYMBOL *NextSym;\r
-\r
- //\r
- // printf ("Free lists.....");\r
- //\r
- // Traverse the include paths, freeing each\r
- // printf ("freeing include paths\n");\r
- //\r
- while (mGlobals.IncludePaths != NULL) {\r
- Temp = mGlobals.IncludePaths->Next;\r
- //\r
- // printf ("Freeing include path string '%s' at 0x%X\n",\r
- // mGlobals.IncludePaths->Str, (int)(mGlobals.IncludePaths->Str));\r
- //\r
- free (mGlobals.IncludePaths->Str);\r
- //\r
- // printf ("Freeing include path object at 0x%X\n", (int)(mGlobals.IncludePaths));\r
- //\r
- free (mGlobals.IncludePaths);\r
- mGlobals.IncludePaths = Temp;\r
- }\r
- //\r
- // Traverse the source files, freeing each\r
- //\r
- while (mGlobals.SourceFiles != NULL) {\r
- Temp = mGlobals.SourceFiles->Next;\r
- free (mGlobals.SourceFiles->Str);\r
- free (mGlobals.SourceFiles);\r
- mGlobals.SourceFiles = Temp;\r
- }\r
- //\r
- // Traverse the subdirectory list, freeing each\r
- //\r
- while (mGlobals.SubDirs != NULL) {\r
- Temp = mGlobals.SubDirs->Next;\r
- free (mGlobals.SubDirs->Str);\r
- free (mGlobals.SubDirs);\r
- mGlobals.SubDirs = Temp;\r
- }\r
- //\r
- // Free the symbol table\r
- //\r
- while (mGlobals.SymbolTable != NULL) {\r
- NextSym = mGlobals.SymbolTable->Next;\r
- free (mGlobals.SymbolTable->Name);\r
- free (mGlobals.SymbolTable->Value);\r
- mGlobals.SymbolTable = NextSym;\r
- }\r
- //\r
- // printf ("done\n");\r
- //\r
-}\r
-\r
-static\r
-void\r
-Usage (\r
- VOID\r
- )\r
-/*++\r
-\r
-Routine Description:\r
-\r
- Print usage information for this utility.\r
- \r
-Arguments:\r
-\r
- None.\r
-\r
-Returns:\r
-\r
- Nothing.\r
- \r
---*/\r
-{\r
- int Index;\r
- static const char *Str[] = {\r
- UTILITY_NAME " -- make dependencies",\r
- " Usage: MakeDeps [options]",\r
- " Options include:",\r
- " -h or -? for this help information",\r
- " -f SourceFile add SourceFile to list of files to scan",\r
- " -i IncludePath add IncludePath to list of search paths",\r
- " -o OutputFile write output dependencies to OutputFile",\r
- " -s SubDir for each IncludePath, also search IncludePath\\SubDir",\r
- " -v for verbose output",\r
- " -ignorenotfound don't warn for files not found",\r
- " -target Target for single SourceFile, target is Target, not SourceFile.obj",\r
- " -q quiet mode to not report files not found if ignored",\r
- " -sub sym str replace all occurrances of 'str' with 'sym' in the output",\r
- " -nosystem not process system <include> files",\r
- " -neverfail always return a success return code",\r
- //\r
- // " -nodupes keep track of include files, don't rescan duplicates",\r
- //\r
- " -usesumdeps path use summary dependency files in 'path' directory.",\r
- "",\r
- NULL\r
- };\r
- for (Index = 0; Str[Index] != NULL; Index++) {\r
- fprintf (stdout, "%s\n", Str[Index]);\r
- }\r
-}\r