Example #1
0
static
STATUS
ProcessFile (
  INT8              *TargetFileName,
  INT8              *FileName,
  UINT32            NestDepth,
  STRING_LIST       *ProcessedFiles,
  FILE_SEARCH_TYPE  FileSearchType
  )
/*++

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.
  FileSearchType - search type for FileName

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;
  STRING_LIST ParentPath;

  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);
      fclose (Fptr);
      return STATUS_SUCCESS;
    }
  }

  //
  // 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);
  
  if (FileSearchType == SearchCurrentDir) {
    //
    // Try to open the source file locally
    //
    if ((Fptr = fopen (FileNameCopy, "r")) == NULL) {
      Error (NULL, 0, 0, FileNameCopy, "could not open source file");
      return STATUS_ERROR;
    }
  } else {
    //
    // Try to find it among the paths.
    //
    Fptr = FindFile (FileNameCopy, sizeof (FileNameCopy), FileSearchType);
    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;
      }
    }
  }

  //
  // 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 (FileNameCopy, 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, FileNameCopy, "duplicate include -- not processed again");
      }
      fclose (Fptr);
      return STATUS_SUCCESS;
    }

    ListPtr       = malloc (sizeof (STRING_LIST));
    ListPtr->Str  = malloc (strlen (FileNameCopy) + 1);
    strcpy (ListPtr->Str, FileNameCopy);
    ListPtr->Next         = ProcessedFiles->Next;
    ProcessedFiles->Next  = ListPtr;
  }
    
  //
  // Print the dependency, with string substitution
  //
  PrintDependency (TargetFileName, FileNameCopy);
  
  //
  // Get the file path and push to ParentPaths
  //
  Cptr = FileNameCopy + strlen (FileNameCopy) - 1;
  for (; (Cptr > FileNameCopy) && (*Cptr != '\\') && (*Cptr != '/'); Cptr--);
  if ((*Cptr == '\\') || (*Cptr == '/')) {
    *(Cptr + 1) = 0;
  } else {
    strcpy (FileNameCopy, ".\\");
  }
  ParentPath.Next = mGlobals.ParentPaths;
  ParentPath.Str = FileNameCopy;
  mGlobals.ParentPaths = &ParentPath;
  
  //
  // 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, there is no # for asm
    //
    if ((*Cptr == '#') || (mGlobals.IsAsm)) {
      if (*Cptr == '#') {
        Cptr++;
      }
      
      //
      // Check for "include", case insensitive for asm
      //
      while (*Cptr && (isspace (*Cptr))) {
        Cptr++;
      }
      if (((!mGlobals.IsAsm) && (strncmp (Cptr, "include", 7) == 0)) || 
          (mGlobals.IsAsm && (_strnicmp (Cptr, "include", 7) == 0))) {
        //
        // Skip over "include" and move on to filename as "file" or <file> or file for asm
        //
        Cptr += 7;
        while (*Cptr && (isspace (*Cptr))) {
          Cptr++;
        }

        if (*Cptr == '<') {
          EndChar = '>';
        } else if (*Cptr == '"') {
          EndChar = '"';
        } else if (mGlobals.IsAsm) {
          //
          // Handle include file for asm
          // Set EndChar to null so we fall through on processing below.
          //
          EndChar = 0;
          
          //
          // Look for the end of include file name
          //
          EndPtr = Cptr;
          while (*EndPtr && (!isspace (*EndPtr))) {
            EndPtr++;
          }
      
          //
          // Null terminate the filename and try to process it.
          //
          *EndPtr = 0;
          Status  = ProcessFile (TargetFileName, Cptr, NestDepth + 1, 
                                 ProcessedFiles, SearchAllPaths);
        } 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, SearchAllPaths);
                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 != '>') {
              //
              // Null terminate the filename and try to process it.
              //
              *EndPtr = 0;
              Status  = ProcessFile (TargetFileName, Cptr, NestDepth + 1, 
                                     ProcessedFiles, SearchAllPaths);
            } else if (!mGlobals.NoSystem) {
              //
              // Null terminate the filename and try to process it.
              //
              *EndPtr = 0;
              Status  = ProcessFile (TargetFileName, Cptr, NestDepth + 1, 
                                     ProcessedFiles, SearchIncludePaths);
            }
          } else {
            Warning (FileNameCopy, LineNum, 0, "malformed include", "missing closing %c", EndChar);
            Status = STATUS_WARNING;
            goto Finish;
          }
        }
      }
    }
  }
  //
  // Pop the file path from ParentPaths
  //
  mGlobals.ParentPaths = ParentPath.Next;  

Finish:
  //
  // Close open files and return status
  //
  if (Fptr != NULL) {
    fclose (Fptr);
  }

  return Status;
}
Example #2
0
static
STATUS
ProcessClOutput (
  INT8            *TargetFileName,
  INT8            *FileName,
  STRING_LIST     *ProcessedFiles
  )
/*++

Routine Description:

  Given a source file name, open the file and parse all "Note: including file: xxx.h" lines.
  
Arguments:

  TargetFileName - name of the usually .obj target
  FileName       - name of the file to process
  ProcessedFiles - list of processed files.

Returns:

  standard status.
  
--*/
{
  FILE        *Fptr;
  INT8        Line[MAX_LINE_LEN];
  INT8        IncludeFileName[MAX_LINE_LEN];
  STRING_LIST *ListPtr;
  BOOLEAN     ClError;
  INT32       Ret;
  INT8        Char;

  if ((Fptr = fopen (FileName, "r")) == NULL) {
    Error (NULL, 0, 0, FileName, "could not open file for reading");
    return STATUS_ERROR;
  }
  if (fgets (Line, sizeof (Line), Fptr) != NULL) {
    //
    // First line is the source file name, print it
    //
    printf ("%s", Line);
  } else {
    //
    // No output from cl
    //
    fclose (Fptr);
    Error (NULL, 0, 0, NULL, "incorrect cl tool path may be used ");
    return STATUS_ERROR;
  }
  
  ClError = FALSE;
  while (fgets (Line, sizeof (Line), Fptr) != NULL) {
    Ret = sscanf (Line, "Note: including file: %s %c", IncludeFileName, &Char);
    if (Ret == 2) {
      //
      // There is space in include file name. It's VS header file. Ignore it.
      //
      continue;
    } else if ( Ret != 1) {
      //
      // Cl error info, print it
      // the tool will return error code to stop the nmake
      //
      ClError = TRUE;
      printf ("%s", Line);
      continue;
    }
    
    //
    // If we're not doing duplicates, and we've already seen this filename,
    // then continue
    //
    if (mGlobals.NoDupes) {
      for (ListPtr = ProcessedFiles->Next; ListPtr != NULL; ListPtr = ListPtr->Next) {
        if (_stricmp (IncludeFileName, 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, IncludeFileName, "duplicate include -- not processed again");
        }
  
        continue;
      }
  
      ListPtr       = malloc (sizeof (STRING_LIST));
      ListPtr->Str  = malloc (strlen (IncludeFileName) + 1);
      strcpy (ListPtr->Str, IncludeFileName);
      ListPtr->Next         = ProcessedFiles->Next;
      ProcessedFiles->Next  = ListPtr;
    }
    
    PrintDependency (TargetFileName, IncludeFileName);
  }
  
  fclose (Fptr);
  
  if (ClError) {
    Error (NULL, 0, 0, NULL, "cl error");
    return STATUS_ERROR;
  } else {
    return STATUS_SUCCESS;
  }
}
Example #3
0
void ProcessFile(
    const string& objectFileName,
    const string& fileName,
    FILE* fp,
    const vector<string>& includePath,
    size_t nesting,
    set<string, less<string> >& cache)
{
    PrintDependency(objectFileName, fileName);

    if (nesting == 100)
    {
        ErrorExit(
            "Infinite include file recursion? nesting level reached 100");
    }

    assert(fp != NULL);

    // For each line in the file:

    char line[4096];
    size_t lineNumber = 1;

    for (; fgets(line, sizeof(line), fp) != NULL; lineNumber++)
    {
        // Check for include directive:

        string path;
        char openDelim;

        if (line[0] == '#' &&
            GetIncludePath(fileName, lineNumber, line, path, openDelim))
        {
            // ATTN: danger! not distinguising between angle brack delimited
            // and quote delimited paths!

            set<string, less<string> >::const_iterator pos
                = cache.find(path);

            if (pos != cache.end())
                continue;

            cache.insert(path);

            string fullPath;
            FILE* fp = FindFile(includePath, path, openDelim, fullPath);

            if (!fp)
            {
                if (warn)
                {
                    Warning("header file not found: " + path +
                        " included from " + objectFileName);
                }
            }
            else
            {
                ProcessFile(objectFileName, fullPath, fp, includePath,
                    nesting + 1, cache);
            }
        }
    }

    fclose(fp);
}