diff --git a/simplecpp.cpp b/simplecpp.cpp index 3cce780..17377f4 100755 --- a/simplecpp.cpp +++ b/simplecpp.cpp @@ -3786,56 +3786,105 @@ void simplecpp::cleanup(std::map &filedata) filedata.clear(); } -std::string simplecpp::getCStdString(const std::string &std) +simplecpp::cstd_t simplecpp::getCStd(const std::string &std) { - if (std == "c90" || std == "c89" || std == "iso9899:1990" || std == "iso9899:199409" || std == "gnu90" || std == "gnu89") { - // __STDC_VERSION__ is not set for C90 although the macro was added in the 1994 amendments - return ""; - } + if (std == "c90" || std == "c89" || std == "iso9899:1990" || std == "iso9899:199409" || std == "gnu90" || std == "gnu89") + return cstd_t::C89; if (std == "c99" || std == "c9x" || std == "iso9899:1999" || std == "iso9899:199x" || std == "gnu99"|| std == "gnu9x") - return "199901L"; + return cstd_t::C99; if (std == "c11" || std == "c1x" || std == "iso9899:2011" || std == "gnu11" || std == "gnu1x") - return "201112L"; + return cstd_t::C11; if (std == "c17" || std == "c18" || std == "iso9899:2017" || std == "iso9899:2018" || std == "gnu17"|| std == "gnu18") - return "201710L"; - if (std == "c23" || std == "gnu23" || std == "c2x" || std == "gnu2x") { - // supported by GCC 9+ and Clang 9+ - // Clang 9, 10, 11, 12, 13 return "201710L" - // Clang 14, 15, 16, 17 return "202000L" - // Clang 9, 10, 11, 12, 13, 14, 15, 16, 17 do not support "c23" and "gnu23" - return "202311L"; + return cstd_t::C17; + if (std == "c23" || std == "gnu23" || std == "c2x" || std == "gnu2x") + return cstd_t::C23; + return cstd_t::CUnknown; +} + +std::string simplecpp::getCStdString(cstd_t std) +{ + switch (std) + { + case cstd_t::C89: + // __STDC_VERSION__ is not set for C90 although the macro was added in the 1994 amendments + return ""; + case cstd_t::C99: + return "199901L"; + case cstd_t::C11: + return "201112L"; + case cstd_t::C17: + return "201710L"; + case cstd_t::C23: + // supported by GCC 9+ and Clang 9+ + // Clang 9, 10, 11, 12, 13 return "201710L" + // Clang 14, 15, 16, 17 return "202000L" + // Clang 9, 10, 11, 12, 13, 14, 15, 16, 17 do not support "c23" and "gnu23" + return "202311L"; + case cstd_t::CUnknown: + return ""; } return ""; } -std::string simplecpp::getCppStdString(const std::string &std) +std::string simplecpp::getCStdString(const std::string &std) +{ + return getCStdString(getCStd(std)); +} + +simplecpp::cppstd_t simplecpp::getCppStd(const std::string &std) { if (std == "c++98" || std == "c++03" || std == "gnu++98" || std == "gnu++03") - return "199711L"; + return cppstd_t::CPP03; if (std == "c++11" || std == "gnu++11" || std == "c++0x" || std == "gnu++0x") - return "201103L"; + return cppstd_t::CPP11; if (std == "c++14" || std == "c++1y" || std == "gnu++14" || std == "gnu++1y") - return "201402L"; + return cppstd_t::CPP14; if (std == "c++17" || std == "c++1z" || std == "gnu++17" || std == "gnu++1z") - return "201703L"; - if (std == "c++20" || std == "c++2a" || std == "gnu++20" || std == "gnu++2a") { - // GCC 10 returns "201703L" - correct in 11+ - return "202002L"; - } - if (std == "c++23" || std == "c++2b" || std == "gnu++23" || std == "gnu++2b") { - // supported by GCC 11+ and Clang 12+ - // GCC 11, 12, 13 return "202100L" - // Clang 12, 13, 14, 15, 16 do not support "c++23" and "gnu++23" and return "202101L" - // Clang 17, 18 return "202302L" - return "202302L"; - } - if (std == "c++26" || std == "c++2c" || std == "gnu++26" || std == "gnu++2c") { - // supported by Clang 17+ - return "202400L"; + return cppstd_t::CPP17; + if (std == "c++20" || std == "c++2a" || std == "gnu++20" || std == "gnu++2a") + return cppstd_t::CPP20; + if (std == "c++23" || std == "c++2b" || std == "gnu++23" || std == "gnu++2b") + return cppstd_t::CPP23; + if (std == "c++26" || std == "c++2c" || std == "gnu++26" || std == "gnu++2c") + return cppstd_t::CPP26; + return cppstd_t::CPPUnknown; +} + +std::string simplecpp::getCppStdString(cppstd_t std) +{ + switch (std) + { + case cppstd_t::CPP03: + return "199711L"; + case cppstd_t::CPP11: + return "201103L"; + case cppstd_t::CPP14: + return "201402L"; + case cppstd_t::CPP17: + return "201703L"; + case cppstd_t::CPP20: + // GCC 10 returns "201703L" - correct in 11+ + return "202002L"; + case cppstd_t::CPP23: + // supported by GCC 11+ and Clang 12+ + // GCC 11, 12, 13 return "202100L" + // Clang 12, 13, 14, 15, 16 do not support "c++23" and "gnu++23" and return "202101L" + // Clang 17, 18 return "202302L" + return "202302L"; + case cppstd_t::CPP26: + // supported by Clang 17+ + return "202400L"; + case cppstd_t::CPPUnknown: + return ""; } return ""; } +std::string simplecpp::getCppStdString(const std::string &std) +{ + return getCppStdString(getCppStd(std)); +} + #if (__cplusplus < 201103L) && !defined(__APPLE__) #undef nullptr #endif diff --git a/simplecpp.h b/simplecpp.h index 88a1401..d664113 100755 --- a/simplecpp.h +++ b/simplecpp.h @@ -39,6 +39,11 @@ #endif namespace simplecpp { + /** C code standard */ + enum cstd_t { CUnknown=-1, C89, C99, C11, C17, C23 }; + + /** C++ code standard */ + enum cppstd_t { CPPUnknown=-1, CPP03, CPP11, CPP14, CPP17, CPP20, CPP23, CPP26 }; typedef std::string TokenString; class Macro; @@ -368,11 +373,19 @@ namespace simplecpp { /** Convert Cygwin path to Windows path */ SIMPLECPP_LIB std::string convertCygwinToWindowsPath(const std::string &cygwinPath); + /** Returns the C version a given standard */ + SIMPLECPP_LIB cstd_t getCStd(const std::string &std); + + /** Returns the C++ version a given standard */ + SIMPLECPP_LIB cppstd_t getCppStd(const std::string &std); + /** Returns the __STDC_VERSION__ value for a given standard */ SIMPLECPP_LIB std::string getCStdString(const std::string &std); + SIMPLECPP_LIB std::string getCStdString(cstd_t std); /** Returns the __cplusplus value for a given standard */ SIMPLECPP_LIB std::string getCppStdString(const std::string &std); + SIMPLECPP_LIB std::string getCppStdString(cppstd_t std); } #if defined(_MSC_VER) diff --git a/test.cpp b/test.cpp index d00658a..6b7cdc9 100644 --- a/test.cpp +++ b/test.cpp @@ -2701,6 +2701,23 @@ static void invalidStd() outputList.clear(); } +static void stdEnum() +{ + ASSERT_EQUALS(simplecpp::cstd_t::C89, simplecpp::getCStd("c89")); + ASSERT_EQUALS(simplecpp::cstd_t::C89, simplecpp::getCStd("c90")); + ASSERT_EQUALS(simplecpp::cstd_t::C11, simplecpp::getCStd("iso9899:2011")); + ASSERT_EQUALS(simplecpp::cstd_t::C23, simplecpp::getCStd("gnu23")); + ASSERT_EQUALS(simplecpp::cstd_t::CUnknown, simplecpp::getCStd("gnu77")); + ASSERT_EQUALS(simplecpp::cstd_t::CUnknown, simplecpp::getCStd("c++11")); + + ASSERT_EQUALS(simplecpp::cppstd_t::CPP03, simplecpp::getCppStd("c++03")); + ASSERT_EQUALS(simplecpp::cppstd_t::CPP03, simplecpp::getCppStd("c++98")); + ASSERT_EQUALS(simplecpp::cppstd_t::CPP17, simplecpp::getCppStd("c++1z")); + ASSERT_EQUALS(simplecpp::cppstd_t::CPP26, simplecpp::getCppStd("gnu++26")); + ASSERT_EQUALS(simplecpp::cppstd_t::CPPUnknown, simplecpp::getCppStd("gnu++77")); + ASSERT_EQUALS(simplecpp::cppstd_t::CPPUnknown, simplecpp::getCppStd("c11")); +} + static void assertToken(const std::string& s, bool name, bool number, bool comment, char op, int line) { const std::vector f; @@ -3030,6 +3047,7 @@ int main(int argc, char **argv) TEST_CASE(stdcVersionDefine); TEST_CASE(cpluscplusDefine); TEST_CASE(invalidStd); + TEST_CASE(stdEnum); TEST_CASE(token);