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