mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-11-04 03:57:26 +00:00 
			
		
		
		
	git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@162 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			1287 lines
		
	
	
		
			35 KiB
		
	
	
	
		
			C
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			1287 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 <Base.h>
 | 
						|
#include <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 > 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)) {
 | 
						|
    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 > 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, TargetFileName);
 | 
						|
  ReplaceSymbols (Str, sizeof (Str));
 | 
						|
  fprintf (mGlobals.OutFptr, "%s : ", Str);
 | 
						|
  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] != '\\') {
 | 
						|
          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] != '\\'); 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] != '\\') {
 | 
						|
          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] != '\\') {
 | 
						|
          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]);
 | 
						|
  }
 | 
						|
}
 |