33 * Copyright (C) 2016-2023 simplecpp team
44 */
55
6+ // needs to be specified here otherwise _mingw.h will define it as 0x0601
7+ // causing FileIdInfo not to be available
68#if defined(_WIN32)
79# ifndef _WIN32_WINNT
810# define _WIN32_WINNT 0x0602
911# endif
10- # ifndef NOMINMAX
11- # define NOMINMAX
12- # endif
13- # ifndef WIN32_LEAN_AND_MEAN
14- # define WIN32_LEAN_AND_MEAN
15- # endif
16- # include < windows.h>
17- # undef ERROR
1812#endif
1913
2014#include " simplecpp.h"
5145#include < utility>
5246#include < vector>
5347
54- #ifdef _WIN32
48+ #if defined(_WIN32)
49+ # ifndef NOMINMAX
50+ # define NOMINMAX
51+ # endif
52+ # ifndef WIN32_LEAN_AND_MEAN
53+ # define WIN32_LEAN_AND_MEAN
54+ # endif
55+ # include < windows.h>
56+ # undef ERROR
5557# include < direct.h>
5658#else
5759# include < sys/stat.h>
60+ # include < sys/types.h>
5861#endif
5962
6063static bool isHex (const std::string &s)
@@ -658,8 +661,6 @@ static const std::string COMMENT_END("*/");
658661
659662void simplecpp::TokenList::readfile (Stream &stream, const std::string &filename, OutputList *outputList)
660663{
661- std::stack<simplecpp::Location> loc;
662-
663664 unsigned int multiline = 0U ;
664665
665666 const Token *oldLastToken = nullptr ;
@@ -698,59 +699,44 @@ void simplecpp::TokenList::readfile(Stream &stream, const std::string &filename,
698699
699700 if (oldLastToken != cback ()) {
700701 oldLastToken = cback ();
701- const Token * const llTok = isLastLinePreprocessor ();
702- if (!llTok)
702+
703+ // #line 3
704+ // #line 3 "file.c"
705+ // #3
706+ // #3 "file.c"
707+ const Token * ppTok = isLastLinePreprocessor ();
708+ if (!ppTok)
703709 continue ;
704- const Token * const llNextToken = llTok->next ;
705- if (!llTok->next )
710+
711+ const auto advanceAndSkipComments = [](const Token* tok) {
712+ do {
713+ tok = tok->next ;
714+ } while (tok && tok->comment );
715+ return tok;
716+ };
717+
718+ // skip #
719+ ppTok = advanceAndSkipComments (ppTok);
720+ if (!ppTok)
706721 continue ;
707- if (llNextToken->next ) {
708- // #file "file.c"
709- if (llNextToken->str () == " file" &&
710- llNextToken->next ->str ()[0 ] == ' \" ' )
711- {
712- const Token *strtok = cback ();
713- while (strtok->comment )
714- strtok = strtok->previous ;
715- loc.push (location);
716- location.fileIndex = fileIndex (strtok->str ().substr (1U , strtok->str ().size () - 2U ));
717- location.line = 1U ;
718- }
719- // TODO: add support for "# 3"
720- // #3 "file.c"
721- // #line 3 "file.c"
722- else if ((llNextToken->number &&
723- llNextToken->next ->str ()[0 ] == ' \" ' ) ||
724- (llNextToken->str () == " line" &&
725- llNextToken->next ->number &&
726- llNextToken->next ->next &&
727- llNextToken->next ->next ->str ()[0 ] == ' \" ' ))
728- {
729- const Token *strtok = cback ();
730- while (strtok->comment )
731- strtok = strtok->previous ;
732- const Token *numtok = strtok->previous ;
733- while (numtok->comment )
734- numtok = numtok->previous ;
735- lineDirective (fileIndex (replaceAll (strtok->str ().substr (1U , strtok->str ().size () - 2U )," \\\\ " ," \\ " )),
736- std::atol (numtok->str ().c_str ()), location);
737- }
738- // #line 3
739- else if (llNextToken->str () == " line" &&
740- llNextToken->next ->number )
741- {
742- const Token *numtok = cback ();
743- while (numtok->comment )
744- numtok = numtok->previous ;
745- lineDirective (location.fileIndex , std::atol (numtok->str ().c_str ()), location);
746- }
747- }
748- // #endfile
749- else if (llNextToken->str () == " endfile" && !loc.empty ())
750- {
751- location = loc.top ();
752- loc.pop ();
753- }
722+
723+ if (ppTok->str () == " line" )
724+ ppTok = advanceAndSkipComments (ppTok);
725+
726+ if (!ppTok || !ppTok->number )
727+ continue ;
728+
729+ const unsigned int line = std::atol (ppTok->str ().c_str ());
730+ ppTok = advanceAndSkipComments (ppTok);
731+
732+ unsigned int fileindex;
733+
734+ if (ppTok && ppTok->str ()[0 ] == ' \" ' )
735+ fileindex = fileIndex (replaceAll (ppTok->str ().substr (1U , ppTok->str ().size () - 2U )," \\\\ " ," \\ " ));
736+ else
737+ fileindex = location.fileIndex ;
738+
739+ lineDirective (fileindex, line, location);
754740 }
755741
756742 continue ;
@@ -1031,16 +1017,15 @@ static bool isAlternativeAndBitandBitor(const simplecpp::Token* tok)
10311017
10321018void simplecpp::TokenList::combineOperators ()
10331019{
1034- std::stack<bool > executableScope;
1035- executableScope.push (false );
1020+ std::stack<bool , std::vector<bool >> executableScope{{false }};
10361021 for (Token *tok = front (); tok; tok = tok->next ) {
10371022 if (tok->op == ' {' ) {
10381023 if (executableScope.top ()) {
10391024 executableScope.push (true );
10401025 continue ;
10411026 }
10421027 const Token *prev = tok->previous ;
1043- while (prev && prev->isOneOf (" ;{}() " ))
1028+ while (prev && prev->isOneOf (" ;{}(" ))
10441029 prev = prev->previous ;
10451030 executableScope.push (prev && prev->op == ' )' );
10461031 continue ;
@@ -2332,9 +2317,6 @@ namespace simplecpp {
23322317 const Token *nextTok = B->next ;
23332318
23342319 if (canBeConcatenatedStringOrChar) {
2335- if (unexpectedA)
2336- throw invalidHashHash::unexpectedToken (tok->location , name (), A);
2337-
23382320 // It seems clearer to handle this case separately even though the code is similar-ish, but we don't want to merge here.
23392321 // TODO The question is whether the ## or varargs may still apply, and how to provoke?
23402322 if (expandArg (tokensB, B, parametertokens)) {
@@ -3090,6 +3072,65 @@ static std::string openHeader(std::ifstream &f, const simplecpp::DUI &dui, const
30903072 return " " ;
30913073}
30923074
3075+ namespace {
3076+ struct FileID {
3077+ #ifdef _WIN32
3078+ struct {
3079+ std::uint64_t VolumeSerialNumber;
3080+ struct {
3081+ std::uint64_t IdentifierHi;
3082+ std::uint64_t IdentifierLo;
3083+ } FileId;
3084+ } fileIdInfo;
3085+
3086+ bool operator ==(const FileID &that) const noexcept {
3087+ return fileIdInfo.VolumeSerialNumber == that.fileIdInfo .VolumeSerialNumber &&
3088+ fileIdInfo.FileId .IdentifierHi == that.fileIdInfo .FileId .IdentifierHi &&
3089+ fileIdInfo.FileId .IdentifierLo == that.fileIdInfo .FileId .IdentifierLo ;
3090+ }
3091+ #else
3092+ dev_t dev;
3093+ ino_t ino;
3094+
3095+ bool operator ==(const FileID& that) const noexcept {
3096+ return dev == that.dev && ino == that.ino ;
3097+ }
3098+ #endif
3099+ struct Hasher {
3100+ std::size_t operator ()(const FileID &id) const {
3101+ #ifdef _WIN32
3102+ return static_cast <std::size_t >(id.fileIdInfo .FileId .IdentifierHi ^ id.fileIdInfo .FileId .IdentifierLo ^
3103+ id.fileIdInfo .VolumeSerialNumber );
3104+ #else
3105+ return static_cast <std::size_t >(id.dev ) ^ static_cast <std::size_t >(id.ino );
3106+ #endif
3107+ }
3108+ };
3109+ };
3110+ }
3111+
3112+ struct simplecpp ::FileDataCache::Impl
3113+ {
3114+ void clear ()
3115+ {
3116+ mIdMap .clear ();
3117+ }
3118+
3119+ using id_map_type = std::unordered_map<FileID, FileData *, FileID::Hasher>;
3120+
3121+ id_map_type mIdMap ;
3122+ };
3123+
3124+ simplecpp::FileDataCache::FileDataCache ()
3125+ : mImpl(new Impl)
3126+ {}
3127+
3128+ simplecpp::FileDataCache::~FileDataCache () = default ;
3129+ simplecpp::FileDataCache::FileDataCache (FileDataCache &&) noexcept = default;
3130+ simplecpp::FileDataCache &simplecpp::FileDataCache::operator =(simplecpp::FileDataCache &&) noexcept = default ;
3131+
3132+ static bool getFileId (const std::string &path, FileID &id);
3133+
30933134std::pair<simplecpp::FileData *, bool > simplecpp::FileDataCache::tryload (FileDataCache::name_map_type::iterator &name_it, const simplecpp::DUI &dui, std::vector<std::string> &filenames, simplecpp::OutputList *outputList)
30943135{
30953136 const std::string &path = name_it->first ;
@@ -3098,8 +3139,8 @@ std::pair<simplecpp::FileData *, bool> simplecpp::FileDataCache::tryload(FileDat
30983139 if (!getFileId (path, fileId))
30993140 return {nullptr , false };
31003141
3101- const auto id_it = mIdMap .find (fileId);
3102- if (id_it != mIdMap .end ()) {
3142+ const auto id_it = mImpl -> mIdMap .find (fileId);
3143+ if (id_it != mImpl -> mIdMap .end ()) {
31033144 name_it->second = id_it->second ;
31043145 return {id_it->second , false };
31053146 }
@@ -3110,9 +3151,12 @@ std::pair<simplecpp::FileData *, bool> simplecpp::FileDataCache::tryload(FileDat
31103151 data->tokens .removeComments ();
31113152
31123153 name_it->second = data;
3113- mIdMap .emplace (fileId, data);
3154+ mImpl -> mIdMap .emplace (fileId, data);
31143155 mData .emplace_back (data);
31153156
3157+ if (mLoadCallback )
3158+ mLoadCallback (*data);
3159+
31163160 return {data, true };
31173161}
31183162
@@ -3162,7 +3206,14 @@ std::pair<simplecpp::FileData *, bool> simplecpp::FileDataCache::get(const std::
31623206 return {nullptr , false };
31633207}
31643208
3165- bool simplecpp::FileDataCache::getFileId (const std::string &path, FileID &id)
3209+ void simplecpp::FileDataCache::clear ()
3210+ {
3211+ mImpl ->clear ();
3212+ mNameMap .clear ();
3213+ mData .clear ();
3214+ }
3215+
3216+ static bool getFileId (const std::string &path, FileID &id)
31663217{
31673218#ifdef _WIN32
31683219 HANDLE hFile = CreateFileA (path.c_str (), 0 , FILE_SHARE_READ | FILE_SHARE_WRITE , nullptr , OPEN_EXISTING , FILE_ATTRIBUTE_NORMAL , nullptr );
@@ -3349,20 +3400,20 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
33493400 std::map<std::string, std::size_t > sizeOfType (rawtokens.sizeOfType );
33503401 sizeOfType.insert (std::make_pair (" char" , sizeof (char )));
33513402 sizeOfType.insert (std::make_pair (" short" , sizeof (short )));
3352- sizeOfType.insert (std::make_pair (" short int" , sizeOfType[ " short" ] ));
3403+ sizeOfType.insert (std::make_pair (" short int" , sizeof ( short ) ));
33533404 sizeOfType.insert (std::make_pair (" int" , sizeof (int )));
33543405 sizeOfType.insert (std::make_pair (" long" , sizeof (long )));
3355- sizeOfType.insert (std::make_pair (" long int" , sizeOfType[ " long" ] ));
3406+ sizeOfType.insert (std::make_pair (" long int" , sizeof ( long ) ));
33563407 sizeOfType.insert (std::make_pair (" long long" , sizeof (long long )));
33573408 sizeOfType.insert (std::make_pair (" float" , sizeof (float )));
33583409 sizeOfType.insert (std::make_pair (" double" , sizeof (double )));
33593410 sizeOfType.insert (std::make_pair (" long double" , sizeof (long double )));
33603411 sizeOfType.insert (std::make_pair (" char *" , sizeof (char *)));
33613412 sizeOfType.insert (std::make_pair (" short *" , sizeof (short *)));
3362- sizeOfType.insert (std::make_pair (" short int *" , sizeOfType[ " short *" ] ));
3413+ sizeOfType.insert (std::make_pair (" short int *" , sizeof ( short *) ));
33633414 sizeOfType.insert (std::make_pair (" int *" , sizeof (int *)));
33643415 sizeOfType.insert (std::make_pair (" long *" , sizeof (long *)));
3365- sizeOfType.insert (std::make_pair (" long int *" , sizeOfType[ " long *" ] ));
3416+ sizeOfType.insert (std::make_pair (" long int *" , sizeof ( long *) ));
33663417 sizeOfType.insert (std::make_pair (" long long *" , sizeof (long long *)));
33673418 sizeOfType.insert (std::make_pair (" float *" , sizeof (float *)));
33683419 sizeOfType.insert (std::make_pair (" double *" , sizeof (double *)));
@@ -3466,8 +3517,19 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL
34663517 includetokenstack.push (rawtokens.cfront ());
34673518 for (auto it = dui.includes .cbegin (); it != dui.includes .cend (); ++it) {
34683519 const FileData *const filedata = cache.get (" " , *it, dui, false , files, outputList).first ;
3469- if (filedata != nullptr && filedata->tokens .cfront () != nullptr )
3520+ if (filedata == nullptr ) {
3521+ if (outputList) {
3522+ simplecpp::Output err{
3523+ simplecpp::Output::EXPLICIT_INCLUDE_NOT_FOUND ,
3524+ {},
3525+ " Can not open include file '" + *it + " ' that is explicitly included."
3526+ };
3527+ outputList->emplace_back (std::move (err));
3528+ }
3529+ }
3530+ else if (filedata->tokens .cfront () != nullptr ) {
34703531 includetokenstack.push (filedata->tokens .cfront ());
3532+ }
34713533 }
34723534
34733535 std::map<std::string, std::list<Location>> maybeUsedMacros;
0 commit comments