|
22 | 22 | #include <exception> |
23 | 23 | #include <fstream> |
24 | 24 | #include <iostream> |
| 25 | +#include <istream> |
25 | 26 | #include <limits> |
26 | 27 | #include <list> |
27 | 28 | #include <map> |
@@ -377,6 +378,42 @@ class StdIStream : public simplecpp::TokenList::Stream { |
377 | 378 | std::istream &istr; |
378 | 379 | }; |
379 | 380 |
|
| 381 | +class StdCharBufStream : public simplecpp::TokenList::Stream { |
| 382 | +public: |
| 383 | + // cppcheck-suppress uninitDerivedMemberVar - we call Stream::init() to initialize the private members |
| 384 | + StdCharBufStream(const unsigned char* str, std::size_t size) |
| 385 | + : str(str) |
| 386 | + , size(size) |
| 387 | + , pos(0) |
| 388 | + , lastStatus(0) |
| 389 | + { |
| 390 | + init(); |
| 391 | + } |
| 392 | + |
| 393 | + virtual int get() OVERRIDE { |
| 394 | + if (pos >= size) |
| 395 | + return lastStatus = EOF; |
| 396 | + return str[pos++]; |
| 397 | + } |
| 398 | + virtual int peek() OVERRIDE { |
| 399 | + if (pos >= size) |
| 400 | + return lastStatus = EOF; |
| 401 | + return str[pos]; |
| 402 | + } |
| 403 | + virtual void unget() OVERRIDE { |
| 404 | + --pos; |
| 405 | + } |
| 406 | + virtual bool good() OVERRIDE { |
| 407 | + return lastStatus != EOF; |
| 408 | + } |
| 409 | + |
| 410 | +private: |
| 411 | + const unsigned char *str; |
| 412 | + const std::size_t size; |
| 413 | + std::size_t pos; |
| 414 | + int lastStatus; |
| 415 | +}; |
| 416 | + |
380 | 417 | class FileStream : public simplecpp::TokenList::Stream { |
381 | 418 | public: |
382 | 419 | // cppcheck-suppress uninitDerivedMemberVar - we call Stream::init() to initialize the private members |
@@ -442,6 +479,20 @@ simplecpp::TokenList::TokenList(std::istream &istr, std::vector<std::string> &fi |
442 | 479 | readfile(stream,filename,outputList); |
443 | 480 | } |
444 | 481 |
|
| 482 | +simplecpp::TokenList::TokenList(const unsigned char* data, std::size_t size, std::vector<std::string> &filenames, const std::string &filename, OutputList *outputList) |
| 483 | + : frontToken(nullptr), backToken(nullptr), files(filenames) |
| 484 | +{ |
| 485 | + StdCharBufStream stream(data, size); |
| 486 | + readfile(stream,filename,outputList); |
| 487 | +} |
| 488 | + |
| 489 | +simplecpp::TokenList::TokenList(const char* data, std::size_t size, std::vector<std::string> &filenames, const std::string &filename, OutputList *outputList) |
| 490 | + : frontToken(nullptr), backToken(nullptr), files(filenames) |
| 491 | +{ |
| 492 | + StdCharBufStream stream(reinterpret_cast<const unsigned char*>(data), size); |
| 493 | + readfile(stream,filename,outputList); |
| 494 | +} |
| 495 | + |
445 | 496 | simplecpp::TokenList::TokenList(const std::string &filename, std::vector<std::string> &filenames, OutputList *outputList) |
446 | 497 | : frontToken(nullptr), backToken(nullptr), files(filenames) |
447 | 498 | { |
@@ -1447,8 +1498,7 @@ namespace simplecpp { |
1447 | 1498 |
|
1448 | 1499 | Macro(const std::string &name, const std::string &value, std::vector<std::string> &f) : nameTokDef(nullptr), files(f), tokenListDefine(f), valueDefinedInCode_(false) { |
1449 | 1500 | const std::string def(name + ' ' + value); |
1450 | | - std::istringstream istr(def); |
1451 | | - StdIStream stream(istr); |
| 1501 | + StdCharBufStream stream(reinterpret_cast<const unsigned char*>(def.data()), def.size()); |
1452 | 1502 | tokenListDefine.readfile(stream); |
1453 | 1503 | if (!parseDefine(tokenListDefine.cfront())) |
1454 | 1504 | throw std::runtime_error("bad macro syntax. macroname=" + name + " value=" + value); |
@@ -3310,11 +3360,24 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL |
3310 | 3360 | macros.insert(std::make_pair("__TIME__", Macro("__TIME__", getTimeDefine(<ime), dummy))); |
3311 | 3361 |
|
3312 | 3362 | if (!dui.std.empty()) { |
3313 | | - std::string std_def = simplecpp::getCStdString(dui.std); |
3314 | | - if (!std_def.empty()) { |
3315 | | - macros.insert(std::make_pair("__STDC_VERSION__", Macro("__STDC_VERSION__", std_def, dummy))); |
| 3363 | + const cstd_t c_std = simplecpp::getCStd(dui.std); |
| 3364 | + if (c_std != CUnknown) { |
| 3365 | + const std::string std_def = simplecpp::getCStdString(c_std); |
| 3366 | + if (!std_def.empty()) |
| 3367 | + macros.insert(std::make_pair("__STDC_VERSION__", Macro("__STDC_VERSION__", std_def, dummy))); |
3316 | 3368 | } else { |
3317 | | - std_def = simplecpp::getCppStdString(dui.std); |
| 3369 | + const cppstd_t cpp_std = simplecpp::getCppStd(dui.std); |
| 3370 | + if (cpp_std == CPPUnknown) { |
| 3371 | + if (outputList) { |
| 3372 | + simplecpp::Output err(files); |
| 3373 | + err.type = Output::DUI_ERROR; |
| 3374 | + err.msg = "unknown standard specified: '" + dui.std + "'"; |
| 3375 | + outputList->push_back(err); |
| 3376 | + } |
| 3377 | + output.clear(); |
| 3378 | + return; |
| 3379 | + } |
| 3380 | + const std::string std_def = simplecpp::getCppStdString(cpp_std); |
3318 | 3381 | if (!std_def.empty()) |
3319 | 3382 | macros.insert(std::make_pair("__cplusplus", Macro("__cplusplus", std_def, dummy))); |
3320 | 3383 | } |
@@ -3463,7 +3526,8 @@ void simplecpp::preprocess(simplecpp::TokenList &output, const simplecpp::TokenL |
3463 | 3526 | std::ifstream f; |
3464 | 3527 | header2 = openHeader(f, dui, rawtok->location.file(), header, systemheader); |
3465 | 3528 | if (f.is_open()) { |
3466 | | - TokenList * const tokens = new TokenList(f, files, header2, outputList); |
| 3529 | + f.close(); |
| 3530 | + TokenList * const tokens = new TokenList(header2, files, outputList); |
3467 | 3531 | if (dui.removeComments) |
3468 | 3532 | tokens->removeComments(); |
3469 | 3533 | filedata[header2] = tokens; |
@@ -3726,56 +3790,105 @@ void simplecpp::cleanup(std::map<std::string, TokenList*> &filedata) |
3726 | 3790 | filedata.clear(); |
3727 | 3791 | } |
3728 | 3792 |
|
3729 | | -std::string simplecpp::getCStdString(const std::string &std) |
| 3793 | +simplecpp::cstd_t simplecpp::getCStd(const std::string &std) |
3730 | 3794 | { |
3731 | | - if (std == "c90" || std == "c89" || std == "iso9899:1990" || std == "iso9899:199409" || std == "gnu90" || std == "gnu89") { |
3732 | | - // __STDC_VERSION__ is not set for C90 although the macro was added in the 1994 amendments |
3733 | | - return ""; |
3734 | | - } |
| 3795 | + if (std == "c90" || std == "c89" || std == "iso9899:1990" || std == "iso9899:199409" || std == "gnu90" || std == "gnu89") |
| 3796 | + return C89; |
3735 | 3797 | if (std == "c99" || std == "c9x" || std == "iso9899:1999" || std == "iso9899:199x" || std == "gnu99"|| std == "gnu9x") |
3736 | | - return "199901L"; |
| 3798 | + return C99; |
3737 | 3799 | if (std == "c11" || std == "c1x" || std == "iso9899:2011" || std == "gnu11" || std == "gnu1x") |
3738 | | - return "201112L"; |
| 3800 | + return C11; |
3739 | 3801 | if (std == "c17" || std == "c18" || std == "iso9899:2017" || std == "iso9899:2018" || std == "gnu17"|| std == "gnu18") |
3740 | | - return "201710L"; |
3741 | | - if (std == "c23" || std == "gnu23" || std == "c2x" || std == "gnu2x") { |
3742 | | - // supported by GCC 9+ and Clang 9+ |
3743 | | - // Clang 9, 10, 11, 12, 13 return "201710L" |
3744 | | - // Clang 14, 15, 16, 17 return "202000L" |
3745 | | - // Clang 9, 10, 11, 12, 13, 14, 15, 16, 17 do not support "c23" and "gnu23" |
3746 | | - return "202311L"; |
| 3802 | + return C17; |
| 3803 | + if (std == "c23" || std == "gnu23" || std == "c2x" || std == "gnu2x") |
| 3804 | + return C23; |
| 3805 | + return CUnknown; |
| 3806 | +} |
| 3807 | + |
| 3808 | +std::string simplecpp::getCStdString(cstd_t std) |
| 3809 | +{ |
| 3810 | + switch (std) |
| 3811 | + { |
| 3812 | + case C89: |
| 3813 | + // __STDC_VERSION__ is not set for C90 although the macro was added in the 1994 amendments |
| 3814 | + return ""; |
| 3815 | + case C99: |
| 3816 | + return "199901L"; |
| 3817 | + case C11: |
| 3818 | + return "201112L"; |
| 3819 | + case C17: |
| 3820 | + return "201710L"; |
| 3821 | + case C23: |
| 3822 | + // supported by GCC 9+ and Clang 9+ |
| 3823 | + // Clang 9, 10, 11, 12, 13 return "201710L" |
| 3824 | + // Clang 14, 15, 16, 17 return "202000L" |
| 3825 | + // Clang 9, 10, 11, 12, 13, 14, 15, 16, 17 do not support "c23" and "gnu23" |
| 3826 | + return "202311L"; |
| 3827 | + case CUnknown: |
| 3828 | + return ""; |
3747 | 3829 | } |
3748 | 3830 | return ""; |
3749 | 3831 | } |
3750 | 3832 |
|
3751 | | -std::string simplecpp::getCppStdString(const std::string &std) |
| 3833 | +std::string simplecpp::getCStdString(const std::string &std) |
| 3834 | +{ |
| 3835 | + return getCStdString(getCStd(std)); |
| 3836 | +} |
| 3837 | + |
| 3838 | +simplecpp::cppstd_t simplecpp::getCppStd(const std::string &std) |
3752 | 3839 | { |
3753 | 3840 | if (std == "c++98" || std == "c++03" || std == "gnu++98" || std == "gnu++03") |
3754 | | - return "199711L"; |
| 3841 | + return CPP03; |
3755 | 3842 | if (std == "c++11" || std == "gnu++11" || std == "c++0x" || std == "gnu++0x") |
3756 | | - return "201103L"; |
| 3843 | + return CPP11; |
3757 | 3844 | if (std == "c++14" || std == "c++1y" || std == "gnu++14" || std == "gnu++1y") |
3758 | | - return "201402L"; |
| 3845 | + return CPP14; |
3759 | 3846 | if (std == "c++17" || std == "c++1z" || std == "gnu++17" || std == "gnu++1z") |
3760 | | - return "201703L"; |
3761 | | - if (std == "c++20" || std == "c++2a" || std == "gnu++20" || std == "gnu++2a") { |
3762 | | - // GCC 10 returns "201703L" - correct in 11+ |
3763 | | - return "202002L"; |
3764 | | - } |
3765 | | - if (std == "c++23" || std == "c++2b" || std == "gnu++23" || std == "gnu++2b") { |
3766 | | - // supported by GCC 11+ and Clang 12+ |
3767 | | - // GCC 11, 12, 13 return "202100L" |
3768 | | - // Clang 12, 13, 14, 15, 16 do not support "c++23" and "gnu++23" and return "202101L" |
3769 | | - // Clang 17, 18 return "202302L" |
3770 | | - return "202302L"; |
3771 | | - } |
3772 | | - if (std == "c++26" || std == "c++2c" || std == "gnu++26" || std == "gnu++2c") { |
3773 | | - // supported by Clang 17+ |
3774 | | - return "202400L"; |
| 3847 | + return CPP17; |
| 3848 | + if (std == "c++20" || std == "c++2a" || std == "gnu++20" || std == "gnu++2a") |
| 3849 | + return CPP20; |
| 3850 | + if (std == "c++23" || std == "c++2b" || std == "gnu++23" || std == "gnu++2b") |
| 3851 | + return CPP23; |
| 3852 | + if (std == "c++26" || std == "c++2c" || std == "gnu++26" || std == "gnu++2c") |
| 3853 | + return CPP26; |
| 3854 | + return CPPUnknown; |
| 3855 | +} |
| 3856 | + |
| 3857 | +std::string simplecpp::getCppStdString(cppstd_t std) |
| 3858 | +{ |
| 3859 | + switch (std) |
| 3860 | + { |
| 3861 | + case CPP03: |
| 3862 | + return "199711L"; |
| 3863 | + case CPP11: |
| 3864 | + return "201103L"; |
| 3865 | + case CPP14: |
| 3866 | + return "201402L"; |
| 3867 | + case CPP17: |
| 3868 | + return "201703L"; |
| 3869 | + case CPP20: |
| 3870 | + // GCC 10 returns "201703L" - correct in 11+ |
| 3871 | + return "202002L"; |
| 3872 | + case CPP23: |
| 3873 | + // supported by GCC 11+ and Clang 12+ |
| 3874 | + // GCC 11, 12, 13 return "202100L" |
| 3875 | + // Clang 12, 13, 14, 15, 16 do not support "c++23" and "gnu++23" and return "202101L" |
| 3876 | + // Clang 17, 18 return "202302L" |
| 3877 | + return "202302L"; |
| 3878 | + case CPP26: |
| 3879 | + // supported by Clang 17+ |
| 3880 | + return "202400L"; |
| 3881 | + case CPPUnknown: |
| 3882 | + return ""; |
3775 | 3883 | } |
3776 | 3884 | return ""; |
3777 | 3885 | } |
3778 | 3886 |
|
| 3887 | +std::string simplecpp::getCppStdString(const std::string &std) |
| 3888 | +{ |
| 3889 | + return getCppStdString(getCppStd(std)); |
| 3890 | +} |
| 3891 | + |
3779 | 3892 | #if (__cplusplus < 201103L) && !defined(__APPLE__) |
3780 | 3893 | #undef nullptr |
3781 | 3894 | #endif |
0 commit comments