@@ -2719,14 +2719,42 @@ static std::string toAbsolutePath(const std::string& path) {
2719
2719
return simplecpp::simplifyPath (path);
2720
2720
}
2721
2721
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 " " ;
2727
2726
}
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;
2730
2758
}
2731
2759
2732
2760
static 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)
3145
3173
return " " ;
3146
3174
}
3147
3175
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 )
3149
3177
{
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);
3156
3189
}
3157
3190
3158
3191
static std::string openHeaderRelative (std::ifstream &f, const std::string &sourcefile, const std::string &header)
3159
3192
{
3160
- return openHeader (f, getRelativeFileName (sourcefile, header));
3193
+ return openHeader (f, getRelativeFileName (sourcefile, header, isAbsolutePath (sourcefile) ));
3161
3194
}
3162
3195
3163
3196
// returns the simplified header path:
@@ -3174,8 +3207,9 @@ static std::string getIncludePathFileName(const std::string &includePath, const
3174
3207
std::string basePath = toAbsolutePath (includePath);
3175
3208
if (!basePath.empty () && basePath[basePath.size ()-1U ]!=' /' && basePath[basePath.size ()-1U ]!=' \\ ' )
3176
3209
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);
3179
3213
}
3180
3214
3181
3215
static 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
3210
3244
if (filedata.find (path) != filedata.end ()) {// try first to respect the exact match
3211
3245
return path;
3212
3246
}
3247
+
3213
3248
// otherwise - try to use the normalize to the correct representation
3249
+ std::string alternativePath;
3214
3250
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));
3222
3252
} 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;
3227
3258
}
3228
- // otherwise
3229
3259
return " " ;
3230
3260
}
3231
3261
@@ -3243,11 +3273,18 @@ static std::string getFileIdPath(const std::map<std::string, simplecpp::TokenLis
3243
3273
}
3244
3274
3245
3275
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 );
3248
3278
if (!match.empty ()) {
3249
3279
return match;
3250
3280
}
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
+ }
3251
3288
} else if (filedata.find (header) != filedata.end ()) {
3252
3289
return header;// system header that its file is already in the filedata - return that as is
3253
3290
}
@@ -3267,6 +3304,16 @@ static bool hasFile(const std::map<std::string, simplecpp::TokenList *> &filedat
3267
3304
return !getFileIdPath (filedata, sourcefile, header, dui, systemheader).empty ();
3268
3305
}
3269
3306
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
+
3270
3317
std::map<std::string, simplecpp::TokenList*> simplecpp::load (const simplecpp::TokenList &rawtokens, std::vector<std::string> &filenames, const simplecpp::DUI &dui, simplecpp::OutputList *outputList)
3271
3318
{
3272
3319
#ifdef SIMPLECPP_WINDOWS
@@ -3343,7 +3390,7 @@ std::map<std::string, simplecpp::TokenList*> simplecpp::load(const simplecpp::To
3343
3390
TokenList *tokens = new TokenList (header2, filenames, outputList);
3344
3391
if (dui.removeComments )
3345
3392
tokens->removeComments ();
3346
- ret[ header2] = tokens;
3393
+ safeInsertTokenListToMap ( ret, header2, tokens, header, rawtok-> location . file (), systemheader, " simplecpp::load " ) ;
3347
3394
if (tokens->front ())
3348
3395
filelist.push_back (tokens->front ());
3349
3396
}
@@ -3630,7 +3677,7 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
3630
3677
TokenList * const tokens = new TokenList (header2, files, outputList);
3631
3678
if (dui.removeComments )
3632
3679
tokens->removeComments ();
3633
- filedata[ header2] = tokens;
3680
+ safeInsertTokenListToMap ( filedata, header2, tokens, header, rawtok-> location . file (), systemheader, " simplecpp::preprocess " ) ;
3634
3681
}
3635
3682
}
3636
3683
if (header2.empty ()) {
0 commit comments