@@ -2719,14 +2719,42 @@ static std::string toAbsolutePath(const std::string& path) {
27192719 return simplecpp::simplifyPath (path);
27202720}
27212721
2722- static std::pair<std::string, bool > extractRelativePathFromAbsolute (const std::string& absolutepath) {
2723- static const std::string prefix = currentDirectory () + " /" ;
2724- if (startsWith_ (absolutepath, prefix)) {
2725- const std::size_t size = prefix.size ();
2726- return std::make_pair (absolutepath.substr (size, absolutepath.size () - size), true );
2722+ static std::string dirPath (const std::string& path, bool withTrailingSlash=true ) {
2723+ const std::size_t lastSlash = path.find_last_of (" \\ /" );
2724+ if (lastSlash == std::string::npos) {
2725+ return " " ;
27272726 }
2728- // otherwise
2729- return std::make_pair (" " , false );
2727+ return path.substr (0 , lastSlash + (withTrailingSlash ? 1U : 0U ));
2728+ }
2729+
2730+ static std::string omitPathTrailingSlash (const std::string& path) {
2731+ if (endsWith (path, " /" )) {
2732+ return path.substr (0 , path.size () - 1U );
2733+ }
2734+ return path;
2735+ }
2736+
2737+ static std::string extractRelativePathFromAbsolute (const std::string& absoluteSimplifiedPath, const std::string& prefixSimplifiedAbsoluteDir = currentDirectory()) {
2738+ const std::string normalizedAbsolutePath = omitPathTrailingSlash (absoluteSimplifiedPath);
2739+ std::string currentPrefix = omitPathTrailingSlash (prefixSimplifiedAbsoluteDir);
2740+ std::string leadingParenting;
2741+ while (!startsWith_ (normalizedAbsolutePath, currentPrefix)) {
2742+ leadingParenting = " ../" + leadingParenting;
2743+ currentPrefix = dirPath (currentPrefix, false );
2744+ }
2745+ const std::size_t size = currentPrefix.size ();
2746+ std::string relativeFromMeetingPath = normalizedAbsolutePath.substr (size, normalizedAbsolutePath.size () - size);
2747+ if (currentPrefix.empty () && !(startsWith_ (absoluteSimplifiedPath, " /" ) && startsWith_ (prefixSimplifiedAbsoluteDir, " /" ))) {
2748+ // In the case that there is no common prefix path,
2749+ // and at not both of the paths start with `/` (can happen only in Windows paths on distinct partitions),
2750+ // return the absolute simplified path as is because no relative path can match.
2751+ return absoluteSimplifiedPath;
2752+ }
2753+ if (startsWith_ (relativeFromMeetingPath, " /" )) {
2754+ // omit the leading slash
2755+ relativeFromMeetingPath = relativeFromMeetingPath.substr (1 , relativeFromMeetingPath.size ());
2756+ }
2757+ return leadingParenting + relativeFromMeetingPath;
27302758}
27312759
27322760static std::string openHeader (std::ifstream &f, const simplecpp::DUI &dui, const std::string &sourcefile, const std::string &header, bool systemheader);
@@ -3145,19 +3173,24 @@ static std::string openHeader(std::ifstream &f, const std::string &path)
31453173 return " " ;
31463174}
31473175
3148- static std::string getRelativeFileName (const std::string &baseFile, const std::string &header)
3176+ static std::string getRelativeFileName (const std::string &baseFile, const std::string &header, bool returnAbsolutePath )
31493177{
3150- std::string path;
3151- if (baseFile.find_first_of (" \\ /" ) != std::string::npos)
3152- path = baseFile.substr (0 , baseFile.find_last_of (" \\ /" ) + 1U ) + header;
3153- else
3154- path = header;
3155- return simplecpp::simplifyPath (path);
3178+ const std::string baseFileSimplified = simplecpp::simplifyPath (baseFile);
3179+ const std::string baseFileAbsolute = isAbsolutePath (baseFileSimplified) ?
3180+ baseFileSimplified :
3181+ simplecpp::simplifyPath (currentDirectory () + " /" + baseFileSimplified);
3182+
3183+ const std::string headerSimplified = simplecpp::simplifyPath (header);
3184+ const std::string path = isAbsolutePath (headerSimplified) ?
3185+ headerSimplified :
3186+ simplecpp::simplifyPath (dirPath (baseFileAbsolute) + headerSimplified);
3187+
3188+ return returnAbsolutePath ? toAbsolutePath (path) : extractRelativePathFromAbsolute (path);
31563189}
31573190
31583191static std::string openHeaderRelative (std::ifstream &f, const std::string &sourcefile, const std::string &header)
31593192{
3160- return openHeader (f, getRelativeFileName (sourcefile, header));
3193+ return openHeader (f, getRelativeFileName (sourcefile, header, isAbsolutePath (sourcefile) ));
31613194}
31623195
31633196// returns the simplified header path:
@@ -3174,8 +3207,9 @@ static std::string getIncludePathFileName(const std::string &includePath, const
31743207 std::string basePath = toAbsolutePath (includePath);
31753208 if (!basePath.empty () && basePath[basePath.size ()-1U ]!=' /' && basePath[basePath.size ()-1U ]!=' \\ ' )
31763209 basePath += ' /' ;
3177- const std::string absolutesimplifiedHeaderPath = basePath + simplifiedHeader;
3178- return extractRelativePathFromAbsolute (absolutesimplifiedHeaderPath).first ;
3210+ const std::string absoluteSimplifiedHeaderPath = simplecpp::simplifyPath (basePath + simplifiedHeader);
3211+ // preserve absoluteness/relativieness of the including dir
3212+ return isAbsolutePath (includePath) ? absoluteSimplifiedHeaderPath : extractRelativePathFromAbsolute (absoluteSimplifiedHeaderPath);
31793213}
31803214
31813215static std::string openHeaderIncludePath (std::ifstream &f, const simplecpp::DUI &dui, const std::string &header)
@@ -3210,22 +3244,18 @@ static std::string findPathInMapBothRelativeAndAbsolute(const std::map<std::stri
32103244 if (filedata.find (path) != filedata.end ()) {// try first to respect the exact match
32113245 return path;
32123246 }
3247+
32133248 // otherwise - try to use the normalize to the correct representation
3249+ std::string alternativePath;
32143250 if (isAbsolutePath (path)) {
3215- const std::pair<std::string, bool > relativeExtractedResult = extractRelativePathFromAbsolute (path);
3216- if (relativeExtractedResult.second ) {
3217- const std::string relativePath = relativeExtractedResult.first ;
3218- if (filedata.find (relativePath) != filedata.end ()) {
3219- return relativePath;
3220- }
3221- }
3251+ alternativePath = extractRelativePathFromAbsolute (simplecpp::simplifyPath (path));
32223252 } else {
3223- const std::string absolutePath = toAbsolutePath (path);
3224- if (filedata.find (absolutePath) != filedata.end ()) {
3225- return absolutePath;
3226- }
3253+ alternativePath = toAbsolutePath (path);
3254+ }
3255+
3256+ if (filedata.find (alternativePath) != filedata.end ()) {
3257+ return alternativePath;
32273258 }
3228- // otherwise
32293259 return " " ;
32303260}
32313261
@@ -3243,11 +3273,18 @@ static std::string getFileIdPath(const std::map<std::string, simplecpp::TokenLis
32433273 }
32443274
32453275 if (!systemheader) {
3246- const std::string relativeOrAbsoluteFilename = getRelativeFileName (sourcefile, header); // unknown if absolute or relative, but always simplified
3247- const std::string match = findPathInMapBothRelativeAndAbsolute (filedata, relativeOrAbsoluteFilename );
3276+ const std::string relativeFilename = getRelativeFileName (sourcefile, header, true );
3277+ const std::string match = findPathInMapBothRelativeAndAbsolute (filedata, relativeFilename );
32483278 if (!match.empty ()) {
32493279 return match;
32503280 }
3281+ // if the file exists but hasn't been loaded yet then we need to stop searching here or we could get a false match
3282+ std::ifstream f;
3283+ openHeader (f, relativeFilename);
3284+ if (f.is_open ()) {
3285+ f.close ();
3286+ return " " ;
3287+ }
32513288 } else if (filedata.find (header) != filedata.end ()) {
32523289 return header;// system header that its file is already in the filedata - return that as is
32533290 }
@@ -3267,6 +3304,16 @@ static bool hasFile(const std::map<std::string, simplecpp::TokenList *> &filedat
32673304 return !getFileIdPath (filedata, sourcefile, header, dui, systemheader).empty ();
32683305}
32693306
3307+ static void safeInsertTokenListToMap (std::map<std::string, simplecpp::TokenList *> &filedata, const std::string &header2, simplecpp::TokenList *tokens, const std::string &header, const std::string &sourcefile, bool systemheader, const char * contextDesc)
3308+ {
3309+ const bool inserted = filedata.insert (std::make_pair (header2, tokens)).second ;
3310+ if (!inserted) {
3311+ std::cerr << " error in " << contextDesc << " - attempt to add a tokenized file to the file map, but this file is already in the map! Details:" <<
3312+ " header: " << header << " header2: " << header2 << " source: " << sourcefile << " systemheader: " << systemheader << std::endl;
3313+ std::abort ();
3314+ }
3315+ }
3316+
32703317std::map<std::string, simplecpp::TokenList*> simplecpp::load (const simplecpp::TokenList &rawtokens, std::vector<std::string> &filenames, const simplecpp::DUI &dui, simplecpp::OutputList *outputList)
32713318{
32723319#ifdef SIMPLECPP_WINDOWS
@@ -3343,7 +3390,7 @@ std::map<std::string, simplecpp::TokenList*> simplecpp::load(const simplecpp::To
33433390 TokenList *tokens = new TokenList (header2, filenames, outputList);
33443391 if (dui.removeComments )
33453392 tokens->removeComments ();
3346- ret[ header2] = tokens;
3393+ safeInsertTokenListToMap ( ret, header2, tokens, header, rawtok-> location . file (), systemheader, " simplecpp::load " ) ;
33473394 if (tokens->front ())
33483395 filelist.push_back (tokens->front ());
33493396 }
@@ -3630,7 +3677,7 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
36303677 TokenList * const tokens = new TokenList (header2, files, outputList);
36313678 if (dui.removeComments )
36323679 tokens->removeComments ();
3633- filedata[ header2] = tokens;
3680+ safeInsertTokenListToMap ( filedata, header2, tokens, header, rawtok-> location . file (), systemheader, " simplecpp::preprocess " ) ;
36343681 }
36353682 }
36363683 if (header2.empty ()) {
0 commit comments