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; }
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; } }
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); }