int loggerGccParserCollectActions( const char* prog_, const char* toolName_, const char* const argv_[], LoggerVector* actions_) { enum Language { C, CPP, OBJC } lang = CPP; size_t i; /* Position of the last include path + 1 */ char full_prog_path[PATH_MAX+1]; char *path_ptr; size_t lastIncPos = 1; size_t lastSysIncPos = 1; GccArgsState state = Normal; LoggerAction* action = loggerActionNew(toolName_); char* keepLinkVar = getenv("CC_LOGGER_KEEP_LINK"); int keepLink = keepLinkVar && strcmp(keepLinkVar, "true") == 0; /* If prog_ is a relative path we try to * convert it to absolute path. */ path_ptr = realpath(prog_, full_prog_path); /* If we cannot convert it, we try to find the * executable in the PATH. */ if (!path_ptr) path_ptr = findFullPath(toolName_, full_prog_path); if (path_ptr) /* Log compiler with full path. */ loggerVectorAdd(&action->arguments, loggerStrDup(full_prog_path)); else /* Compiler was not found in path, log the binary name only. */ loggerVectorAdd(&action->arguments, loggerStrDup(toolName_)); /* Determine programming language based on compiler name. */ for (i = 0; cCompiler[i]; ++i) if (strstr(toolName_, cCompiler[i])) lang = C; for (i = 0; cppCompiler[i]; ++i) if (strstr(toolName_, cppCompiler[i])) lang = CPP; for (i = 1; argv_[i]; ++i) { const char* current = argv_[i]; state = processArgument(state, current, action); if (current[0] == '-') { /* Determine the position of the last -I and -isystem flags. * Depending on whether the parameter of -I or -isystem is separated * from the flag by a space character. * 2 == strlen("-I") && 8 == strlen("-isystem") */ if (current[1] == 'I') lastIncPos = action->arguments.size + (current[2] ? 0 : 1); else if (strstr(current, "-isystem") == current) lastSysIncPos = action->arguments.size + (current[8] ? 0 : 1); /* Determine the programming language based on -x flag. */ else if (strcmp(current, "-x") == 0) { /* TODO: The language value after -x can be others too. See the man * page of GCC. * TODO: According to a GCC warning the -x flag has no effect when it * is placed after the last input file to be compiled. */ const char* l = argv_[i + 1]; if (strcmp(l, "c") == 0 || strcmp(l, "c-header") == 0) lang = C; else if (strcmp(l, "c++") == 0 || strcmp(l, "c++-header") == 0) lang = CPP; } } } if (getenv("CC_LOGGER_DEF_DIRS")) { LoggerVector defIncludes; loggerVectorInit(&defIncludes); getDefaultArguments(prog_, &defIncludes); if (defIncludes.size) { loggerVectorAddFrom(&action->arguments, &defIncludes, &lastIncPos, (LoggerDupFuc) &loggerStrDup); if (lastSysIncPos > lastIncPos) lastSysIncPos += defIncludes.size; lastIncPos += defIncludes.size; } loggerVectorClear(&defIncludes); } if (getenv("CPATH")) { LoggerVector includes; loggerVectorInit(&includes); getPathsFromEnvVar(&includes, "CPATH", "-I"); if (includes.size) { loggerVectorAddFrom(&action->arguments, &includes, &lastIncPos, (LoggerDupFuc) &loggerStrDup); if (lastSysIncPos > lastIncPos) lastSysIncPos += includes.size; lastIncPos += includes.size; } loggerVectorClear(&includes); } if (lang == CPP && getenv("CPLUS_INCLUDE_PATH")) { LoggerVector includes; loggerVectorInit(&includes); getPathsFromEnvVar(&includes, "CPLUS_INCLUDE_PATH", "-isystem"); if (includes.size) { loggerVectorAddFrom(&action->arguments, &includes, &lastSysIncPos, (LoggerDupFuc) &loggerStrDup); } loggerVectorClear(&includes); } else if (lang == C && getenv("C_INCLUDE_PATH")) { LoggerVector includes; loggerVectorInit(&includes); getPathsFromEnvVar(&includes, "C_INCLUDE_PATH", "-isystem"); if (includes.size) { loggerVectorAddFrom(&action->arguments, &includes, &lastSysIncPos, (LoggerDupFuc) &loggerStrDup); } loggerVectorClear(&includes); } /* * Workaround for -MT and friends: if the source set contains the output, * then we have to remove it from the set. */ i = loggerVectorFind(&action->sources, action->output.path, (LoggerCmpFuc) &strcmp); if (i != SIZE_MAX) { loggerVectorErase(&action->sources, i); } if (!keepLink) do { i = loggerVectorFindIf(&action->sources, (LoggerPredFuc) &isObjectFile); loggerVectorErase(&action->sources, i); } while (i != SIZE_MAX); if (action->sources.size != 0) loggerVectorAdd(actions_, action); return 1; }
int loggerGccParserCollectActions( const char* prog_, const char* toolName_, const char* const argv_[], LoggerVector* actions_) { size_t i; /* Position of the last include path + 1 */ size_t lastIncPos = 1; GccArgsState state = Normal; LoggerAction* action = loggerActionNew(toolName_); loggerVectorAdd(&action->arguments, loggerStrDup(toolName_)); for (i = 1; argv_[i]; ++i) { state = processArgument(state, argv_[i], action); if (argv_[i][0] == '-' && argv_[i][1] == 'I') { if (argv_[i][2]) { /* -I with path argument */ lastIncPos = action->arguments.size; } else { /* The path should be the next argument */ lastIncPos = action->arguments.size + 1; } } } if (!getenv("CC_LOGGER_NO_DEF_DIRS")) { LoggerVector defIncludes; loggerVectorInit(&defIncludes); getDefaultArguments(prog_, &defIncludes); if (defIncludes.size) { loggerVectorAddFrom(&action->arguments, &defIncludes, &lastIncPos, (LoggerDupFuc) &loggerStrDup); } loggerVectorClear(&defIncludes); } /* * Workaround for -MT and friends: if the source set contains the output, * then we have to remove it from the set. */ i = loggerVectorFind(&action->sources, action->output.path, (LoggerCmpFuc) &strcmp); if (i != SIZE_MAX) { loggerVectorErase(&action->sources, i); } loggerVectorAdd(actions_, action); return 1; }
void runApplicationTest(char *applicationPath, const char *testName, LinkedList testArguments, ReturnCodes expectedResultCode, boolByte anazyleOutput) { char** applicationArguments; ArgumentsCopyData argumentsCopyData; int resultCode = -1; LinkedList defaultArguments = getDefaultArguments(testName); LinkedList arguments = _appendLinkedLists(defaultArguments, testArguments); CharString failedAnalysisFunctionName = newCharString(); unsigned long failedAnalysisSample; // Remove any output files which may have been left from previous tests foreachItemInList(defaultArguments, _removeOutputFile, NULL); #if WINDOWS #else mkdir("out", 0755); #endif #if WINDOWS logUnsupportedFeature("Application testing"); #else int numArgs = numItemsInList(arguments); // Add two extra items to the array, one for the application path and another for a NULL object. // These are required for the calls to the execv* functions. applicationArguments = (char**)malloc(sizeof(char*) * (numArgs + 2)); applicationArguments[0] = applicationPath; applicationArguments[numArgs + 1] = NULL; argumentsCopyData.currentIndex = 1; argumentsCopyData.outArray = applicationArguments; foreachItemInList(arguments, _copyArgumentToArray, &argumentsCopyData); printf(" %s: ", testName); pid_t forkedPid = fork(); if(forkedPid == 0) { resultCode = execvp(applicationPath, applicationArguments); exit(resultCode); } else { int statusLoc; waitpid(forkedPid, &statusLoc, 0); if(WIFEXITED(statusLoc)) { resultCode = WEXITSTATUS(statusLoc); } } #endif if(resultCode == expectedResultCode) { if(anazyleOutput) { if(analyzeFile(_getTestOutputFilename(testName, "pcm"), failedAnalysisFunctionName, &failedAnalysisSample)) { testsPassed++; foreachItemInList(defaultArguments, _removeOutputFile, NULL); printTestSuccess(); } else { printTestFail(); printf(" in test '%s', while analyzing output for %s at sample %lu.\n", testName, failedAnalysisFunctionName->data, failedAnalysisSample); testsFailed++; } } else { testsPassed++; foreachItemInList(defaultArguments, _removeOutputFile, NULL); printTestSuccess(); } } else { printTestFail(); printf(" in %s. Expected result code %d, got %d.\n", testName, expectedResultCode, resultCode); testsFailed++; } freeLinkedList(defaultArguments); freeLinkedList(testArguments); freeLinkedList(arguments); }