2015-02-26 15:02:31 +00:00
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#include <libgen.h>
|
|
|
|
|
#include <stdlib.h>
|
2016-10-06 18:54:06 +00:00
|
|
|
|
#include <sstream>
|
2022-07-20 16:38:42 +00:00
|
|
|
|
#include <cstring>
|
2015-02-26 15:02:31 +00:00
|
|
|
|
|
|
|
|
|
#include "Utilities.hh"
|
|
|
|
|
|
2017-05-18 13:42:40 +00:00
|
|
|
|
std::string sanitize(const std::string& text) {
|
|
|
|
|
std::string result = text;
|
|
|
|
|
for (char c : {'<', '>', ' ', ',', ':', '*', '[', ']'}) {
|
|
|
|
|
std::replace(result.begin(), result.end(), c, '_');
|
|
|
|
|
}
|
2022-05-25 18:08:11 +00:00
|
|
|
|
// Catches templates with negative default values (iss #660)
|
|
|
|
|
for (char c : {'-'}) {
|
|
|
|
|
std::replace(result.begin(), result.end(), c, 'n');
|
|
|
|
|
}
|
2017-05-18 13:42:40 +00:00
|
|
|
|
return result ;
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-01 20:55:19 +00:00
|
|
|
|
// Replace special chars for xml output
|
|
|
|
|
std::string & replace_special_chars( std::string & str) {
|
|
|
|
|
|
|
|
|
|
// escape &
|
|
|
|
|
size_t index = 0;
|
|
|
|
|
while (index != std::string::npos) {
|
|
|
|
|
index = str.find("&" , index) ;
|
|
|
|
|
if ( index != std::string::npos ) {
|
|
|
|
|
str.replace(index, 1, "&") ;
|
|
|
|
|
index += 5;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// escape "
|
|
|
|
|
index = 0;
|
|
|
|
|
while (index != std::string::npos) {
|
|
|
|
|
index = str.find("\\\"" , index) ;
|
|
|
|
|
if ( index != std::string::npos ) {
|
|
|
|
|
str.replace(index, 2, """) ;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// escape <
|
|
|
|
|
index = 0;
|
|
|
|
|
while (index != std::string::npos) {
|
|
|
|
|
index = str.find("<" , index) ;
|
|
|
|
|
if ( index != std::string::npos ) {
|
|
|
|
|
str.replace(index, 1, "<") ;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return str;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-26 15:02:31 +00:00
|
|
|
|
// removes leading and trailing whitespace from a string
|
|
|
|
|
std::string trim(const std::string& str, const std::string& whitespace ) {
|
|
|
|
|
size_t strBegin = str.find_first_not_of(whitespace);
|
|
|
|
|
if (strBegin == std::string::npos) {
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
size_t strEnd = str.find_last_not_of(whitespace);
|
|
|
|
|
size_t strRange = strEnd - strBegin + 1;
|
|
|
|
|
|
|
|
|
|
return str.substr(strBegin, strRange);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isInUserCode( clang::CompilerInstance & ci , clang::SourceLocation sl , HeaderSearchDirs & hsd ) {
|
|
|
|
|
bool ret = false ;
|
2024-10-15 15:37:03 +00:00
|
|
|
|
char* resolved_path = getResolvedPath(ci, sl);
|
|
|
|
|
|
|
|
|
|
if ( resolved_path != NULL ) {
|
|
|
|
|
if ( hsd.isPathInUserDir(resolved_path)) {
|
|
|
|
|
ret = true ;
|
2015-02-26 15:02:31 +00:00
|
|
|
|
}
|
2024-10-15 15:37:03 +00:00
|
|
|
|
free(resolved_path) ;
|
2015-02-26 15:02:31 +00:00
|
|
|
|
}
|
2024-10-15 15:37:03 +00:00
|
|
|
|
|
2015-02-26 15:02:31 +00:00
|
|
|
|
return ret ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool isInUserOrTrickCode( clang::CompilerInstance & ci , clang::SourceLocation sl , HeaderSearchDirs & hsd ) {
|
|
|
|
|
bool ret = false ;
|
2024-10-15 15:37:03 +00:00
|
|
|
|
char* resolved_path = getResolvedPath(ci, sl);
|
|
|
|
|
|
|
|
|
|
if ( resolved_path != NULL ) {
|
|
|
|
|
if ( hsd.isPathInUserOrTrickDir(resolved_path)) {
|
|
|
|
|
ret = true ;
|
2015-02-26 15:02:31 +00:00
|
|
|
|
}
|
2024-10-15 15:37:03 +00:00
|
|
|
|
free(resolved_path) ;
|
2015-02-26 15:02:31 +00:00
|
|
|
|
}
|
2024-10-15 15:37:03 +00:00
|
|
|
|
|
2015-02-26 15:02:31 +00:00
|
|
|
|
return ret ;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string getFileName( clang::CompilerInstance & ci , clang::SourceLocation sl , HeaderSearchDirs & hsd ) {
|
2018-11-06 17:23:12 +00:00
|
|
|
|
std::string file_name;
|
2024-10-15 15:37:03 +00:00
|
|
|
|
char* resolved_path = getResolvedPath(ci, sl);
|
|
|
|
|
|
|
|
|
|
if (resolved_path != NULL ) {
|
|
|
|
|
if (hsd.isPathInUserDir(resolved_path)) {
|
|
|
|
|
file_name.append(resolved_path);
|
|
|
|
|
}
|
|
|
|
|
free(resolved_path);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return file_name;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
char * getResolvedPath(clang::CompilerInstance & ci , clang::SourceLocation sl) {
|
|
|
|
|
clang::FileID fid = ci.getSourceManager().getFileID(sl) ;
|
|
|
|
|
char* resolved_path = NULL;
|
|
|
|
|
|
2015-02-26 15:02:31 +00:00
|
|
|
|
if ( ! fid.isInvalid() ) {
|
|
|
|
|
const clang::FileEntry * fe = ci.getSourceManager().getFileEntryForID(fid) ;
|
|
|
|
|
if ( fe != NULL ) {
|
2020-10-22 03:33:53 +00:00
|
|
|
|
#if (LIBCLANG_MAJOR < 4) // TODO delete when RHEL 7 no longer supported
|
2024-10-15 15:37:03 +00:00
|
|
|
|
resolved_path = almostRealPath( fe->getName() ) ;
|
|
|
|
|
#elif (LIBCLANG_MAJOR >= 4 && LIBCLANG_MAJOR < 18)
|
|
|
|
|
resolved_path = almostRealPath( fe->getName().str() ) ;
|
2020-10-22 03:33:53 +00:00
|
|
|
|
#else
|
2024-10-15 15:37:03 +00:00
|
|
|
|
const clang::CustomizableOptional<clang::FileEntryRef> cfer = ci.getSourceManager().getFileEntryRefForID(fid) ;
|
|
|
|
|
if (cfer.has_value()) {
|
|
|
|
|
resolved_path = almostRealPath( cfer->getName().str() ) ;
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-22 03:33:53 +00:00
|
|
|
|
#endif
|
2015-02-26 15:02:31 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2024-10-15 15:37:03 +00:00
|
|
|
|
|
|
|
|
|
return resolved_path;
|
2015-02-26 15:02:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#include <iostream>
|
2016-10-21 20:06:35 +00:00
|
|
|
|
char * almostRealPath( const std::string& in_path ) {
|
|
|
|
|
return almostRealPath(in_path.c_str());
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-26 15:02:31 +00:00
|
|
|
|
/*
|
|
|
|
|
This function returns almost absolute path of the directory of the incoming path.
|
|
|
|
|
It does not follow the last symbolic link.
|
|
|
|
|
|
|
|
|
|
dirname and basename may modify their argument, so make a copy of the path.
|
|
|
|
|
*/
|
|
|
|
|
char * almostRealPath( const char * in_path ) {
|
|
|
|
|
char * file_copy_path = strdup(in_path) ;
|
|
|
|
|
char * dir_copy_path = strdup(in_path) ;
|
|
|
|
|
char * file = basename(file_copy_path) ;
|
|
|
|
|
char * dir = dirname(dir_copy_path) ;
|
|
|
|
|
char * resolved_path = NULL ;
|
|
|
|
|
char * final_path = NULL ;
|
|
|
|
|
resolved_path = realpath( dir , resolved_path) ;
|
|
|
|
|
if ( resolved_path != NULL ) {
|
2022-11-15 21:00:05 +00:00
|
|
|
|
size_t final_path_len = strlen(resolved_path) + strlen(file) + 2;
|
|
|
|
|
final_path = (char *)malloc(final_path_len) ;
|
|
|
|
|
snprintf(final_path, final_path_len, "%s/%s", resolved_path , file ) ;
|
2015-02-26 15:02:31 +00:00
|
|
|
|
free(resolved_path) ;
|
|
|
|
|
}
|
|
|
|
|
free(file_copy_path) ;
|
|
|
|
|
free(dir_copy_path) ;
|
2017-03-15 20:53:56 +00:00
|
|
|
|
|
|
|
|
|
if (!final_path) {
|
|
|
|
|
std::cout << bold(color(WARNING, "Warning")) << " ICG could not resolve realpath of " << quote(bold(in_path)) << std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
2015-02-26 15:02:31 +00:00
|
|
|
|
return final_path ;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-06 18:54:06 +00:00
|
|
|
|
static const std::string escapeSequence = "[";
|
|
|
|
|
static const std::string defaultForegroundColorSequence = escapeSequence + "39m";
|
|
|
|
|
static const std::string boldSequence = escapeSequence + "1m";
|
2019-04-09 18:18:02 +00:00
|
|
|
|
static const std::string noBoldSequence = escapeSequence + "22m";
|
2016-10-06 18:54:06 +00:00
|
|
|
|
static const std::string underlineSequence = escapeSequence + "4m";
|
|
|
|
|
static const std::string noUnderlineSequence = escapeSequence + "24m";
|
|
|
|
|
|
|
|
|
|
std::string color(const Color& color, const std::string& text) {
|
|
|
|
|
std::ostringstream oss;
|
|
|
|
|
oss << escapeSequence << color << "m" << text << defaultForegroundColorSequence;
|
|
|
|
|
return oss.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string bold(const std::string& text) {
|
|
|
|
|
return boldSequence + text + noBoldSequence;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string underline(const std::string& text) {
|
|
|
|
|
return underlineSequence + text + noUnderlineSequence;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string underline(const std::string& text, unsigned length) {
|
|
|
|
|
return underline(text.substr(0, length)) + text.substr(length);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::string quote(const std::string& text) {
|
|
|
|
|
return "\"" + text + "\"";
|
|
|
|
|
}
|
2022-07-20 16:38:42 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// This function will accept version numbers with Major, Major.Minor, or Major.Minor.Patch.
|
|
|
|
|
// It removes non-numerical prefixes or postfixes to the version number. The return value
|
|
|
|
|
// is an int with the format MMmmpp, which is what llvm LangOpts.gnucversion expects.
|
|
|
|
|
// If there is a problem or no verno is provided, it returns the default value.
|
|
|
|
|
int gccVersionToIntOrDefault(const char* verno, int def) {
|
|
|
|
|
const int buffersize = 32;
|
|
|
|
|
// need mutable characters for strtok
|
|
|
|
|
char verbuf[buffersize];
|
|
|
|
|
if(verno == nullptr || verno[0] == '\0' || strlen(verno) >= buffersize) {
|
|
|
|
|
// Invalid GCC version string, returning default GCC version
|
|
|
|
|
return def;
|
|
|
|
|
}
|
|
|
|
|
strcpy(verbuf, verno);
|
|
|
|
|
const int len = strlen(verbuf);
|
|
|
|
|
const char* majMinPatch[3] = {"0", "0", "0"};
|
|
|
|
|
// Setting non-numerals to the delimeter (might catch vernos with prefix or postfix)
|
|
|
|
|
for(int i = 0; i < len; i++) {
|
|
|
|
|
if(verbuf[i] < '0' || verbuf[i] > '9') {
|
|
|
|
|
verbuf[i] = '.';
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
char* next = strtok(verbuf, ".");
|
|
|
|
|
for(int i = 0; next != nullptr && i < 3; i++) {
|
|
|
|
|
majMinPatch[i] = next;
|
|
|
|
|
next = strtok(nullptr, ".");
|
|
|
|
|
}
|
|
|
|
|
// This is the format that LLVM expects for the version number
|
|
|
|
|
int result = 10000*atoi(majMinPatch[0]) + 100*atoi(majMinPatch[1]) + atoi(majMinPatch[2]);
|
|
|
|
|
if(result > 999999) {
|
|
|
|
|
std::cerr << "Warning: GCC_VERSION is invalid version number: " << result << ". Setting ICG to use default GCC version: " << def << std::endl;
|
|
|
|
|
return def;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|