Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/libs/wave/test/testwave/testwave_app.cpp @ 29

Last change on this file since 29 was 29, checked in by landauf, 16 years ago

updated boost from 1_33_1 to 1_34_1

File size: 43.8 KB
Line 
1/*=============================================================================
2    Boost.Wave: A Standard compliant C++ preprocessor library
3    http://www.boost.org/
4
5    Copyright (c) 2001-2006 Hartmut Kaiser. Distributed under the Boost
6    Software License, Version 1.0. (See accompanying file
7    LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8=============================================================================*/
9
10// system headers
11#include <string>
12#include <iostream>
13#include <vector>
14
15// include boost
16#include <boost/config.hpp>
17#include <boost/throw_exception.hpp>
18#include <boost/filesystem/path.hpp>
19#include <boost/filesystem/operations.hpp>
20#include <boost/detail/workaround.hpp>
21
22//  include Wave
23#include <boost/wave.hpp>
24
25//  include the lexer related stuff
26#include <boost/wave/cpplexer/cpp_lex_token.hpp>      // token type
27#include <boost/wave/cpplexer/cpp_lex_iterator.hpp>   // lexer type
28
29//  test application related headers
30#include "cmd_line_utils.hpp"
31#include "testwave_app.hpp"
32
33namespace po = boost::program_options;
34namespace fs = boost::filesystem;
35
36///////////////////////////////////////////////////////////////////////////////
37// testwave version definitions
38#define TESTWAVE_VERSION_MAJOR           0
39#define TESTWAVE_VERSION_MINOR           4
40#define TESTWAVE_VERSION_SUBMINOR        0
41
42///////////////////////////////////////////////////////////////////////////////
43// workaround for missing ostringstream
44#ifdef BOOST_NO_STRINGSTREAM
45#include <strstream>
46#define BOOST_WAVETEST_OSSTREAM std::ostrstream
47std::string BOOST_WAVETEST_GETSTRING(std::ostrstream& ss)
48{
49    ss << ends;
50    std::string rval = ss.str();
51    ss.freeze(false);
52    return rval;
53}
54#else
55#include <sstream>
56#define BOOST_WAVETEST_GETSTRING(ss) ss.str()
57#define BOOST_WAVETEST_OSSTREAM std::ostringstream
58#endif
59
60namespace {
61
62    ///////////////////////////////////////////////////////////////////////////
63    template <typename Iterator>
64    inline bool 
65    handle_next_token(Iterator &it, Iterator const& end, 
66        std::string &result)
67    {
68        typedef typename Iterator::value_type token_type;
69       
70        token_type tok = *it++;   
71        result = result + tok.get_value().c_str();
72        return (it == end) ? false : true;
73    }
74
75    ///////////////////////////////////////////////////////////////////////////
76    template <typename String>
77    String const& handle_quoted_filepath(String &name)
78    {
79        using boost::wave::util::impl::unescape_lit;
80       
81        String unesc_name = unescape_lit(name.substr(1, name.size()-2));
82        fs::path p (unesc_name.c_str(), fs::native);
83
84        name = String("\"") + p.leaf().c_str() + String("\"");
85        return name;
86    }
87
88    ///////////////////////////////////////////////////////////////////////////
89    template <typename String>
90    String const& handle_filepath(String &name)
91    {
92        using boost::wave::util::impl::unescape_lit;
93       
94        String unesc_name = unescape_lit(name);
95        fs::path p (unesc_name.c_str(), fs::native);
96
97        name = p.leaf().c_str();
98        return name;
99    }
100
101    ///////////////////////////////////////////////////////////////////////////
102    template <typename Iterator>
103    bool handle_line_directive(Iterator &it, Iterator const& end, 
104        std::string &result)
105    {
106        typedef typename Iterator::value_type token_type;
107        typedef typename token_type::string_type string_type;
108       
109        if (!handle_next_token(it, end, result) ||  // #line
110            !handle_next_token(it, end, result) ||  // whitespace
111            !handle_next_token(it, end, result) ||  // number
112            !handle_next_token(it, end, result))    // whitespace
113        {
114            return false;
115        }
116       
117        using boost::wave::util::impl::unescape_lit;
118       
119        token_type filename = *it;
120        string_type name = filename.get_value();
121
122        handle_quoted_filepath(name);
123        result = result + name.c_str();
124        return true;
125    }
126}
127
128///////////////////////////////////////////////////////////////////////////
129//
130//  This function compares the real result and the expected one but first
131//  replaces all occurences in the expected result of
132//      $E: to the result of preprocessing the given expression
133//      $F: to the passed full filepath
134//      $P: to the full path
135//      $V: to the current Boost version number
136//
137///////////////////////////////////////////////////////////////////////////
138bool 
139testwave_app::got_expected_result(std::string const& filename, 
140    std::string const& result, std::string& expected)
141{
142    using boost::wave::util::impl::escape_lit;
143   
144    std::string full_result;
145    std::string::size_type pos = 0;
146    std::string::size_type pos1 = expected.find_first_of("$");
147   
148    if (pos1 != std::string::npos) {
149        do {
150            switch(expected[pos1+1]) {
151            case 'E':       // preprocess the given token sequence
152                {
153                    if ('(' == expected[pos1+2]) {
154                        std::size_t p = expected.find_first_of(")", pos1+1);
155                        if (std::string::npos == p) {
156                            std::cerr
157                                << "testwave: unmatched parenthesis in $E"
158                                    " directive" << std::endl;
159                            return false;
160                        }
161                        std::string source = expected.substr(pos1+3, p-pos1-3);
162                        std::string result, error;
163                        bool pp_result = preprocess_file(filename, source, 
164                            result, error, true);
165                        if (!pp_result) {
166                            std::cerr
167                                << "testwave: preprocessing error in $E directive: " 
168                                << error << std::endl;
169                            return false;
170                        }
171                        full_result = full_result + 
172                            expected.substr(pos, pos1-pos) + result;
173                        pos1 = expected.find_first_of ("$", 
174                            pos = pos1 + 4 + source.size());
175                    }
176                }
177                break;
178               
179            case 'F':       // insert base file name
180                full_result = full_result + 
181                    expected.substr(pos, pos1-pos) + escape_lit(filename);
182                pos1 = expected.find_first_of ("$", pos = pos1 + 2);
183                break;
184
185            case 'P':       // insert full path
186                {
187                    fs::path fullpath = fs::complete(
188                        fs::path(filename, fs::native), 
189                        fs::current_path());
190                    if ('(' == expected[pos1+2]) {
191                    // the $P(basename) syntax is used
192                        std::size_t p = expected.find_first_of(")", pos1+1);
193                        if (std::string::npos == p) {
194                            std::cerr
195                                << "testwave: unmatched parenthesis in $P"
196                                    " directive" << std::endl;
197                            return false;
198                        }
199                        std::string base = expected.substr(pos1+3, p-pos1-3);
200                        fullpath = fullpath.branch_path() / 
201                            fs::path(base, fs::native);
202                        full_result = full_result + 
203                            expected.substr(pos, pos1-pos) + 
204                            escape_lit(fullpath.normalize().native_file_string());
205                        pos1 = expected.find_first_of ("$", 
206                            pos = pos1 + 4 + base.size());
207                    }
208                    else {
209                    // the $P is used on its own
210                        full_result = full_result + 
211                            expected.substr(pos, pos1-pos) + 
212                            escape_lit(fullpath.native_file_string());
213                        pos1 = expected.find_first_of ("$", pos = pos1 + 2);
214                    }
215                }
216                break;
217               
218            case 'V':       // insert Boost version
219                full_result = full_result + 
220                    expected.substr(pos, pos1-pos) + BOOST_LIB_VERSION;
221                pos1 = expected.find_first_of ("$", pos = pos1 + 2);
222                break;
223               
224            default:
225                full_result = full_result +
226                    expected.substr(pos, pos1-pos);
227                pos1 = expected.find_first_of ("$", (pos = pos1) + 1);
228                break;
229            }
230
231        } while(pos1 != std::string::npos);
232        full_result += expected.substr(pos);
233    }
234    else {
235        full_result = expected;
236    }
237   
238    expected = full_result;
239    return full_result == result;
240}
241
242///////////////////////////////////////////////////////////////////////////////
243testwave_app::testwave_app(po::variables_map const& vm)
244:   debuglevel(1), desc_options("Preprocessor configuration options"), 
245    global_vm(vm)
246{
247    desc_options.add_options()
248        ("include,I", po::value<cmd_line_utils::include_paths>()->composing(), 
249            "specify an additional include directory")
250        ("sysinclude,S", po::value<std::vector<std::string> >()->composing(), 
251            "specify an additional system include directory")
252        ("define,D", po::value<std::vector<std::string> >()->composing(), 
253            "specify a macro to define (as macro[=[value]])")
254        ("predefine,P", po::value<std::vector<std::string> >()->composing(), 
255            "specify a macro to predefine (as macro[=[value]])")
256        ("undefine,U", po::value<std::vector<std::string> >()->composing(), 
257            "specify a macro to undefine")
258        ("nesting,n", po::value<int>(), 
259            "specify a new maximal include nesting depth")
260        ("long_long", "enable long long support in C++ mode")
261        ("preserve", "preserve comments")
262#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
263        ("variadics", "enable certain C99 extensions in C++ mode")
264        ("c99", "enable C99 mode (implies --variadics)")
265#endif
266#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
267        ("noguard,G", "disable include guard detection")
268#endif
269    ;
270}
271
272///////////////////////////////////////////////////////////////////////////////
273//
274//  Test the given file (i.e. preprocess the file and compare the result
275//  against the embedded 'R' comments, if an error occurs compare the error
276//  message against the given 'E' comments).
277//
278///////////////////////////////////////////////////////////////////////////////
279bool 
280testwave_app::test_a_file(std::string filename)
281{
282// read the input file into a string
283    std::string instr;
284    if (!read_file(filename, instr)) 
285        return false;     // error was reported already
286
287// extract expected output, preprocess the data and compare results
288    std::string expected;
289    if (extract_expected_output(filename, instr, expected)) {
290        bool retval = true;   // assume success
291        std::string result, error;
292        bool pp_result = preprocess_file(filename, instr, result, error);
293        if (pp_result || !result.empty()) {
294        // did we expect an error?
295            std::string expected_error;
296            if (!extract_special_information(filename, instr, 'E', expected_error))
297                return false;
298
299            if (!expected_error.empty() && 
300                !got_expected_result(filename, error, expected_error))
301            {
302            // we expected an error but got none (or a different one)
303                if (debuglevel > 2) {
304                    std::cerr
305                        << filename << ": failed" << std::endl
306                        << "result: " << std::endl << result << std::endl;
307
308                    if (!error.empty()) {
309                        std::cerr << "expected result: " << std::endl
310                                  << expected << std::endl;
311                    }
312                    if (!expected_error.empty()) {
313                        std::cerr << "expected error: " << std::endl
314                                  << expected_error << std::endl;
315                    }
316                }
317                else if (debuglevel > 1) {
318                    std::cerr << filename << ": failed" << std::endl;
319                }
320                retval = false;
321            }
322            else if (!got_expected_result(filename, result, expected)) {
323            //  no preprocessing error encountered
324                if (debuglevel > 2) {
325                    std::cerr
326                        << filename << ": failed" << std::endl
327                        << "result: " << std::endl << result << std::endl
328                        << "expected: " << std::endl << expected << std::endl;
329                }
330                else if (debuglevel > 1) {
331                    std::cerr << filename << ": failed" << std::endl;
332                }
333                retval = false;
334            }
335            else if (debuglevel > 4) {
336                std::cerr
337                    << filename << ": succeeded" << std::endl
338                    << "result: " << std::endl << result << std::endl;
339            }
340            else if (debuglevel > 3) {
341                std::cerr << filename << ": succeeded" << std::endl;
342            }
343        }
344       
345        if (!pp_result) {
346        //  there was a preprocessing error, was it expected?
347            std::string expected_error;
348            if (!extract_special_information(filename, instr, 'E', expected_error))
349                return false;
350               
351            if (!got_expected_result(filename, error, expected_error)) {
352            // the error was unexpected
353                if (debuglevel > 2) {
354                    std::cerr
355                        << filename << ": failed" << std::endl;
356
357                    if (!expected_error.empty()) {
358                        std::cerr
359                            << "result: " << std::endl << error << std::endl
360                            << "expected error: " << std::endl
361                            << expected_error << std::endl;
362                    }
363                    else {
364                        std::cerr << "unexpected error: " << error << std::endl;
365                    }
366                }
367                else if (debuglevel > 1) {
368                    std::cerr << filename << ": failed" << std::endl;
369                }
370                retval = false;
371            }
372            else if (debuglevel > 4) {
373                std::cerr
374                    << filename << ": succeeded" << std::endl
375                    << "result: " << std::endl << error << std::endl;
376            }
377            else if (debuglevel > 3) {
378            // caught the expected error message
379                std::cerr << filename << ": succeeded" << std::endl;
380            }
381        }
382        return retval;
383    }
384    else {
385        std::cerr
386            << filename << ": no information about expected results found"
387            << std::endl;
388    }
389    return false;
390}
391
392///////////////////////////////////////////////////////////////////////////////
393//
394//  print the current version of this program
395//
396///////////////////////////////////////////////////////////////////////////////
397int 
398testwave_app::print_version()
399{
400// get time of last compilation of this file
401boost::wave::util::time_conversion_helper compilation_time(__DATE__ " " __TIME__);
402
403// calculate the number of days since Feb 12 2005
404// (the day the testwave project was started)
405std::tm first_day;
406
407    using namespace std;      // some platforms have memset in namespace std
408    memset (&first_day, 0, sizeof(std::tm));
409    first_day.tm_mon = 1;           // Feb
410    first_day.tm_mday = 12;         // 12
411    first_day.tm_year = 105;        // 2005
412
413long seconds = long(std::difftime(compilation_time.get_time(), 
414    std::mktime(&first_day)));
415
416    std::cout
417        << TESTWAVE_VERSION_MAJOR << '.' 
418        << TESTWAVE_VERSION_MINOR << '.'
419        << TESTWAVE_VERSION_SUBMINOR << '.'
420        << seconds/(3600*24)        // get number of days from seconds
421        << std::endl;
422    return 0;                       // exit app
423}
424
425///////////////////////////////////////////////////////////////////////////////
426//
427//  print the copyright statement
428//
429///////////////////////////////////////////////////////////////////////////////
430int 
431testwave_app::print_copyright()
432{
433    char const *copyright[] = {
434        "",
435        "Testwave: A test driver for the Boost.Wave C++ preprocessor library",
436        "http://www.boost.org/",
437        "",
438        "Copyright (c) 2001-2006 Hartmut Kaiser, Distributed under the Boost",
439        "Software License, Version 1.0. (See accompanying file",
440        "LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)",
441        0
442    };
443   
444    for (int i = 0; 0 != copyright[i]; ++i)
445        std::cout << copyright[i] << std::endl;
446       
447    return 0;                       // exit app
448}
449
450///////////////////////////////////////////////////////////////////////////////
451//
452//  Read the given file into a string
453//
454///////////////////////////////////////////////////////////////////////////////
455bool 
456testwave_app::read_file(std::string const& filename, std::string& instr)
457{
458// open the given file and report error, if appropriate
459    std::ifstream instream(filename.c_str());
460    if (!instream.is_open()) {
461        std::cerr << "testwave: could not open input file: " 
462                  << filename << std::endl;
463        return false;
464    }
465    else if (9 == debuglevel) {
466        std::cerr << "read_file: succeeded to open input file: " 
467                  << filename << std::endl;
468    }
469    instream.unsetf(std::ios::skipws);
470
471// read the input file into a string
472   
473#if defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS)
474// this is known to be very slow for large files on some systems
475    std::copy (std::istream_iterator<char>(instream),
476        std::istream_iterator<char>(), 
477        std::inserter(instr, instr.end()));
478#else
479    instr = std::string(std::istreambuf_iterator<char>(instream.rdbuf()),
480        std::istreambuf_iterator<char>());
481#endif
482   
483    if (9 == debuglevel) {
484        std::cerr << "read_file: succeeded to read input file: " 
485                  << filename << std::endl;
486    }
487    return true;
488}
489
490///////////////////////////////////////////////////////////////////////////////
491namespace {
492
493    std::string const& trim_whitespace(std::string& value)
494    {
495        std::string::size_type first = value.find_first_not_of(" \t");
496        if (std::string::npos == first) 
497            value.clear();
498        else {
499            std::string::size_type last = value.find_last_not_of(" \t");
500            assert(std::string::npos != last);
501            value = value.substr(first, last-first+1);
502        }
503        return value;
504    }
505}
506
507///////////////////////////////////////////////////////////////////////////////
508//
509//  Extract special information from comments marked with the given letter
510//
511///////////////////////////////////////////////////////////////////////////////
512bool 
513testwave_app::extract_special_information(std::string const& filename, 
514    std::string const& instr, char flag, std::string& content)
515{
516    if (9 == debuglevel) {
517        std::cerr << "extract_special_information: extracting special information ('" 
518                  << flag << "') from input file: " << filename << std::endl;
519    }
520
521// tokenize the input data into C++ tokens using the C++ lexer
522    typedef boost::wave::cpplexer::lex_token<> token_type;
523    typedef boost::wave::cpplexer::lex_iterator<token_type> lexer_type;
524    typedef token_type::position_type position_type;
525   
526    boost::wave::language_support const lang_opts = 
527        (boost::wave::language_support)(
528            boost::wave::support_option_variadics | 
529            boost::wave::support_option_long_long |
530            boost::wave::support_option_no_character_validation |
531            boost::wave::support_option_convert_trigraphs);
532   
533    position_type pos(filename.c_str());
534    lexer_type it = lexer_type(instr.begin(), instr.end(), pos, lang_opts);
535    lexer_type end = lexer_type();
536
537    try {
538    // look for C or C++ comments starting with the special character
539        for (/**/; it != end; ++it) {
540            using namespace boost::wave;
541            token_id id = token_id(*it);
542            if (T_CCOMMENT == id) {
543                std::string value = (*it).get_value().c_str();
544                if (flag == value[2]) {
545                    if (value.size() > 3 && '(' == value[3]) {
546                        std::size_t p = value.find_first_of(")");
547                        if (std::string::npos == p) {
548                            std::cerr
549                                << "testwave: missing closing parenthesis in '"
550                                << flag << "()' directive" << std::endl;
551                            return false;
552                        }
553                        std::string source = value.substr(4, p-4);
554                        std::string result, error;
555                        bool pp_result = preprocess_file(filename, source, 
556                            result, error, true);
557                        if (!pp_result) {
558                            std::cerr
559                                << "testwave: preprocessing error in '" << flag
560                                << "()' directive: " << error << std::endl;
561                            return false;
562                        }
563                       
564                        // include this text into the extracted information
565                        // only if the result is not zero
566                        using namespace std;    // some system have atoi in namespace std
567                        if (0 != atoi(result.c_str())) {
568                            std::string thiscontent(value.substr(p+1));
569                            if (9 == debuglevel) {
570                                std::cerr << "extract_special_information: extracted: " 
571                                          << thiscontent << std::endl;
572                            }
573                            trim_whitespace(thiscontent);
574                            content += thiscontent;
575                        }
576                    }
577                    else {
578                        std::string thiscontent(value.substr(3, value.size()-5));
579                        if (9 == debuglevel) {
580                            std::cerr << "extract_special_information: extracted: " 
581                                      << thiscontent << std::endl;
582                        }
583                        trim_whitespace(thiscontent);
584                        content += thiscontent;
585                    }
586                }
587            }
588            else if (T_CPPCOMMENT == id) {
589                std::string value = (*it).get_value().c_str();
590                if (flag == value[2]) {
591                    if (value.size() > 3 && '(' == value[3]) {
592                        std::size_t p = value.find_first_of(")");
593                        if (std::string::npos == p) {
594                            std::cerr
595                                << "testwave: missing closing parenthesis in '"
596                                << flag << "()' directive" << std::endl;
597                            return false;
598                        }
599                        std::string source = value.substr(4, p-4);
600                        std::string result, error;
601                        bool pp_result = preprocess_file(filename, source, 
602                            result, error, true);
603                        if (!pp_result) {
604                            std::cerr
605                                << "testwave: preprocessing error in '" << flag
606                                << "()' directive: " << error << std::endl;
607                            return false;
608                        }
609                       
610                        // include this text into the extracted information
611                        // only if the result is not zero
612                        using namespace std;    // some system have atoi in namespace std
613                        if (0 != atoi(result.c_str())) {
614                            std::string thiscontent(value.substr((' ' == value[p+1]) ? p+2 : p+1));
615                            if (9 == debuglevel) {
616                                std::cerr << "extract_special_information: extracted: " 
617                                          << thiscontent << std::endl;
618                            }
619                            trim_whitespace(thiscontent);
620                            content += thiscontent;
621                        }
622                    }
623                    else {
624                        std::string thiscontent(value.substr((' ' == value[3]) ? 4 : 3));
625                        if (9 == debuglevel) {
626                            std::cerr << "extract_special_information: extracted: " 
627                                      << thiscontent;
628                        }
629                        trim_whitespace(content);
630                        content += thiscontent;
631                    }
632                }
633            }
634        }
635    }
636    catch (boost::wave::cpplexer::lexing_exception const &e) {
637    // some lexing error
638        std::cerr
639            << e.file_name() << "(" << e.line_no() << "): "
640            << e.description() << std::endl;
641        return false;
642    }
643
644    if (9 == debuglevel) {
645        std::cerr << "extract_special_information: succeeded extracting special information ('" 
646                  << flag << "')" << std::endl;
647    }
648    return true;
649}
650
651///////////////////////////////////////////////////////////////////////////////
652//
653//  Extract the expected output from the given input data
654//
655//  The expected output has to be provided inside of special comments which
656//  start with a capital 'R'. All such comments are concatenated and returned
657//  through the parameter 'expected'.
658//
659///////////////////////////////////////////////////////////////////////////////
660inline bool 
661testwave_app::extract_expected_output(std::string const& filename, 
662    std::string const& instr, std::string& expected)
663{
664    return extract_special_information(filename, instr, 'R', expected);
665}
666
667///////////////////////////////////////////////////////////////////////////////
668//
669//  Extracts the required preprocessing options from the given input data and
670//  initialises the given Wave context object accordingly.
671//  We allow the same (applicable) options to be used as are valid for the wave
672//  driver executable.
673//
674///////////////////////////////////////////////////////////////////////////////
675template <typename Context>
676bool 
677testwave_app::extract_options(std::string const& filename, 
678    std::string const& instr, Context& ctx, bool single_line)
679{
680    if (9 == debuglevel) {
681        std::cerr << "extract_options: extracting options" << std::endl;
682    }
683
684//  extract the required information from the comments flagged by a
685//  capital 'O'
686    std::string options;
687    if (!extract_special_information(filename, instr, 'O', options))
688        return false;
689
690    try {       
691    //  parse the configuration information into a program_options_description
692    //  object
693        po::variables_map local_vm;
694        cmd_line_utils::read_config_options(debuglevel, options, desc_options, local_vm);
695        initialise_options(ctx, local_vm, single_line);
696    }
697    catch (std::exception const &e) {
698        std::cerr << filename << ": exception caught: " << e.what() 
699                  << std::endl;
700        return false;
701    }
702   
703    if (9 == debuglevel) {
704        std::cerr << "extract_options: succeeded extracting options" 
705                  << std::endl;
706    }
707
708    return true;
709}
710
711namespace {
712
713    template <typename T>
714    inline T const&
715    variables_map_as(po::variable_value const& v, T*)
716    {
717#if (__GNUC__ == 3 && (__GNUC_MINOR__ == 2 || __GNUC_MINOR__ == 3)) || \
718    BOOST_WORKAROUND(__MWERKS__, < 0x3200)
719// gcc 3.2.x and  3.3.x choke on vm[...].as<...>()
720// CW 8.3 has problems with the v.as<T>() below
721        T const* r = boost::any_cast<T>(&v.value());
722        if (!r)
723            boost::throw_exception(boost::bad_any_cast());
724        return *r;
725#else
726        return v.as<T>();
727#endif
728    }
729}
730
731template <typename Context>
732bool 
733testwave_app::initialise_options(Context& ctx, po::variables_map const& vm,
734    bool single_line)
735{
736    if (9 == debuglevel) {
737        std::cerr << "initialise_options: initializing options" << std::endl;
738    }
739
740//  initialize the given context from the parsed options
741#if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
742// enable C99 mode, if appropriate (implies variadics)
743    if (vm.count("c99")) {
744        if (9 == debuglevel) {
745            std::cerr << "initialise_options: option: c99" << std::endl;
746        }
747        ctx.set_language(
748            boost::wave::language_support(
749                boost::wave::support_c99
750              | boost::wave::support_option_emit_line_directives
751#if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
752              | boost::wave::support_option_include_guard_detection
753#endif
754            ));
755    }
756    else if (vm.count("variadics")) {
757    // enable variadics and placemarkers, if appropriate
758        if (9 == debuglevel) {
759            std::cerr << "initialise_options: option: variadics" << std::endl;
760        }
761        ctx.set_language(boost::wave::enable_variadics(ctx.get_language()));
762    }
763#endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
764
765// enable long_long mode, if appropriate
766    if (vm.count("long_long")) {
767        if (9 == debuglevel) {
768            std::cerr << "initialise_options: option: long_long" << std::endl;
769        }
770        ctx.set_language(boost::wave::enable_long_long(ctx.get_language()));
771    }
772   
773// enable preserving comments mode, if appropriate
774    if (vm.count("preserve")) {
775        if (9 == debuglevel) {
776            std::cerr << "initialise_options: option: preserve" << std::endl;
777        }
778        ctx.set_language(
779            boost::wave::enable_preserve_comments(ctx.get_language()));
780    }
781   
782// disable automatic include guard detection
783    if (vm.count("noguard")) {
784        if (9 == debuglevel) {
785            std::cerr << "initialise_options: option: guard" << std::endl;
786        }
787        ctx.set_language(
788            boost::wave::enable_include_guard_detection(ctx.get_language(), false));
789    }
790   
791// enable trigraph conversion
792    if (9 == debuglevel) {
793        std::cerr << "initialise_options: option: convert_trigraphs" << std::endl;
794    }
795    ctx.set_language(boost::wave::enable_convert_trigraphs(ctx.get_language()));
796
797// enable single_line mode
798    if (single_line) {
799        if (9 == debuglevel) {
800            std::cerr << "initialise_options: option: single_line" << std::endl;
801        }
802        ctx.set_language(boost::wave::enable_single_line(ctx.get_language()));
803    }
804   
805//  add include directories to the system include search paths
806    if (vm.count("sysinclude")) {
807    std::vector<std::string> const& syspaths = 
808        variables_map_as(vm["sysinclude"], (std::vector<std::string> *)NULL);
809   
810        std::vector<std::string>::const_iterator end = syspaths.end();
811        for (std::vector<std::string>::const_iterator cit = syspaths.begin(); 
812              cit != end; ++cit)
813        {
814            if (9 == debuglevel) {
815                std::cerr << "initialise_options: option: -S" << *cit
816                          << std::endl;
817            }
818            ctx.add_sysinclude_path((*cit).c_str());
819        }
820    }
821   
822//  add include directories to the user include search paths
823    if (vm.count("include")) {
824        cmd_line_utils::include_paths const &ip = 
825            variables_map_as(vm["include"], (cmd_line_utils::include_paths*)NULL);
826        std::vector<std::string>::const_iterator end = ip.paths.end();
827
828        for (std::vector<std::string>::const_iterator cit = ip.paths.begin(); 
829              cit != end; ++cit)
830        {
831            if (9 == debuglevel) {
832                std::cerr << "initialise_options: option: -I" << *cit
833                          << std::endl;
834            }
835            ctx.add_include_path((*cit).c_str());
836        }
837
838    // if on the command line was given -I- , this has to be propagated
839        if (ip.seen_separator) {
840            if (9 == debuglevel) {
841                std::cerr << "initialise_options: option: -I-" << std::endl;
842            }
843            ctx.set_sysinclude_delimiter();
844        }
845       
846    // add system include directories to the include path
847        std::vector<std::string>::const_iterator sysend = ip.syspaths.end();
848        for (std::vector<std::string>::const_iterator syscit = ip.syspaths.begin(); 
849              syscit != sysend; ++syscit)
850        {
851            if (9 == debuglevel) {
852                std::cerr << "initialise_options: option: -S" << *syscit
853                          << std::endl;
854            }
855            ctx.add_sysinclude_path((*syscit).c_str());
856        }
857    }
858
859//  add additional defined macros
860    if (vm.count("define")) {
861        std::vector<std::string> const &macros = 
862            variables_map_as(vm["define"], (std::vector<std::string>*)NULL);
863        std::vector<std::string>::const_iterator end = macros.end();
864        for (std::vector<std::string>::const_iterator cit = macros.begin(); 
865              cit != end; ++cit)
866        {
867            if (9 == debuglevel) {
868                std::cerr << "initialise_options: option: -D" << *cit
869                          << std::endl;
870            }
871            ctx.add_macro_definition(*cit);
872        }
873    }
874
875//  add additional predefined macros
876    if (vm.count("predefine")) {
877        std::vector<std::string> const &predefmacros = 
878            variables_map_as(vm["predefine"], (std::vector<std::string>*)NULL);
879        std::vector<std::string>::const_iterator end = predefmacros.end();
880        for (std::vector<std::string>::const_iterator cit = predefmacros.begin(); 
881              cit != end; ++cit)
882        {
883            if (9 == debuglevel) {
884                std::cerr << "initialise_options: option: -P" << *cit
885                          << std::endl;
886            }
887            ctx.add_macro_definition(*cit);
888        }
889    }
890
891//  undefine specified macros
892    if (vm.count("undefine")) {
893        std::vector<std::string> const &undefmacros = 
894            variables_map_as(vm["undefine"], (std::vector<std::string>*)NULL);
895        std::vector<std::string>::const_iterator end = undefmacros.end();
896        for (std::vector<std::string>::const_iterator cit = undefmacros.begin(); 
897              cit != end; ++cit)
898        {
899            if (9 == debuglevel) {
900                std::cerr << "initialise_options: option: -U" << *cit
901                          << std::endl;
902            }
903            ctx.remove_macro_definition((*cit).c_str());
904        }
905    }
906
907//  maximal include nesting depth
908    if (vm.count("nesting")) {
909        int max_depth = variables_map_as(vm["nesting"], (int*)NULL);
910        if (max_depth < 1 || max_depth > 100000) {
911            std::cerr << "testwave: bogus maximal include nesting depth: " 
912                << max_depth << std::endl;
913            return false;
914        }
915        else if (9 == debuglevel) {
916            std::cerr << "initialise_options: option: -n" << max_depth
917                      << std::endl;
918        }
919        ctx.set_max_include_nesting_depth(max_depth);
920    }
921
922    if (9 == debuglevel) {
923        std::cerr << "initialise_options: succeeded to initialize options" 
924                  << std::endl;
925    }
926    return true;
927}
928
929///////////////////////////////////////////////////////////////////////////////
930//  construct a SIZEOF macro definition string and predefine this macro
931template <typename Context>
932inline bool 
933testwave_app::add_sizeof_definition(Context& ctx, char const *name, int value)
934{
935    BOOST_WAVETEST_OSSTREAM strm;
936    strm << "__TESTWAVE_SIZEOF_" << name << "__=" << value;
937
938    std::string macro(BOOST_WAVETEST_GETSTRING(strm));
939    if (!ctx.add_macro_definition(macro)) {
940        std::cerr << "testwave: failed to predefine macro: " << macro
941                  << std::endl;
942        return false;
943    }
944    else if (9 == debuglevel) {
945        std::cerr << "add_sizeof_definition: predefined macro: " << macro
946                  << std::endl;
947    }
948    return true;
949}
950
951//  construct a MIN macro definition string and predefine this macro
952template <typename T, typename Context>
953inline bool 
954testwave_app::add_min_definition(Context& ctx, char const *name)
955{
956    BOOST_WAVETEST_OSSTREAM strm;
957    if (!std::numeric_limits<T>::is_signed) {
958        strm << "__TESTWAVE_" << name << "_MIN__=" 
959              << "0x" << std::hex
960              << (std::numeric_limits<T>::min)() << "U";
961    }
962    else {
963        strm << "__TESTWAVE_" << name << "_MIN__=( " 
964              << (std::numeric_limits<T>::min)()+1 << "-1)";
965    }
966   
967    std::string macro(BOOST_WAVETEST_GETSTRING(strm));
968    if (!ctx.add_macro_definition(macro)) {
969        std::cerr << "testwave: failed to predefine macro: " << macro
970                  << std::endl;
971        return false;
972    }
973    else if (9 == debuglevel) {
974        std::cerr << "add_min_definition: predefined macro: " << macro
975                  << std::endl;
976    }
977    return true;
978}
979
980//  construct a MAX macro definition string and predefine this macro
981template <typename T, typename Context>
982inline bool 
983testwave_app::add_max_definition(Context& ctx, char const *name)
984{
985    BOOST_WAVETEST_OSSTREAM strm;
986    if (!std::numeric_limits<T>::is_signed) {
987        strm << "__TESTWAVE_" << name << "_MAX__=" 
988              << "0x" << std::hex
989              << (std::numeric_limits<T>::max)() << "U";
990    }
991    else {
992        strm << "__TESTWAVE_" << name << "_MAX__=" 
993              << (std::numeric_limits<T>::max)();
994    }
995   
996    std::string macro(BOOST_WAVETEST_GETSTRING(strm));
997    if (!ctx.add_macro_definition(macro)) {
998        std::cerr << "testwave: failed to predefine macro: " << macro
999                  << std::endl;
1000        return false;
1001    }
1002    else if (9 == debuglevel) {
1003        std::cerr << "add_max_definition: predefined macro: " << macro
1004                  << std::endl;
1005    }
1006    return true;
1007}
1008
1009//  Predefine __TESTWAVE_HAS_STRICT_LEXER__
1010template <typename Context>
1011inline bool 
1012testwave_app::add_strict_lexer_definition(Context& ctx)
1013{
1014    std::string macro("__TESTWAVE_HAS_STRICT_LEXER__=1");
1015    if (!ctx.add_macro_definition(macro)) {
1016        std::cerr << "testwave: failed to predefine macro: " << macro
1017                  << std::endl;
1018        return false;
1019    }
1020    else if (9 == debuglevel) {
1021        std::cerr << "add_strict_lexer_definition: predefined macro: " << macro
1022                  << std::endl;
1023    }
1024    return true;
1025}
1026
1027///////////////////////////////////////////////////////////////////////////////
1028//
1029//  Add special predefined macros to the context object.
1030//
1031//  This adds a lot of macros to the test environment, which allows to adjust
1032//  the test cases for different platforms.
1033//
1034///////////////////////////////////////////////////////////////////////////////
1035template <typename Context>
1036bool 
1037testwave_app::add_predefined_macros(Context& ctx)
1038{
1039    // add the __TESTWAVE_SIZEOF_<type>__ macros
1040    if (!add_sizeof_definition(ctx, "CHAR", sizeof(char)) ||
1041        !add_sizeof_definition(ctx, "SHORT", sizeof(short)) ||
1042        !add_sizeof_definition(ctx, "INT", sizeof(int)) ||
1043#if defined(BOOST_HAS_LONG_LONG)
1044        !add_sizeof_definition(ctx, "LONGLONG", sizeof(boost::long_long_type)) ||
1045#endif
1046        !add_sizeof_definition(ctx, "LONG", sizeof(long)))
1047    {
1048        std::cerr << "testwave: failed to add a predefined macro (SIZEOF)." 
1049                  << std::endl;
1050        return false;
1051    }
1052   
1053    // add the __TESTWAVE_<type>_MIN__ macros
1054    if (/*!add_min_definition<char>(ctx, "CHAR") ||*/
1055        /*!add_min_definition<unsigned char>(ctx, "UCHAR") ||*/
1056        !add_min_definition<short>(ctx, "SHORT") ||
1057        !add_min_definition<unsigned short>(ctx, "USHORT") ||
1058        !add_min_definition<int>(ctx, "INT") ||
1059        !add_min_definition<unsigned int>(ctx, "UINT") ||
1060#if defined(BOOST_HAS_LONG_LONG)
1061        !add_min_definition<boost::long_long_type>(ctx, "LONGLONG") ||
1062        !add_min_definition<boost::ulong_long_type>(ctx, "ULONGLONG") ||
1063#endif
1064        !add_min_definition<long>(ctx, "LONG") ||
1065        !add_min_definition<unsigned long>(ctx, "ULONG"))
1066    {
1067        std::cerr << "testwave: failed to add a predefined macro (MIN)." 
1068                  << std::endl;
1069    }
1070   
1071    // add the __TESTWAVE_<type>_MAX__ macros
1072    if (/*!add_max_definition<char>(ctx, "CHAR") ||*/
1073        /*!add_max_definition<unsigned char>(ctx, "UCHAR") ||*/
1074        !add_max_definition<short>(ctx, "SHORT") ||
1075        !add_max_definition<unsigned short>(ctx, "USHORT") ||
1076        !add_max_definition<int>(ctx, "INT") ||
1077        !add_max_definition<unsigned int>(ctx, "UINT") ||
1078#if defined(BOOST_HAS_LONG_LONG)
1079        !add_max_definition<boost::long_long_type>(ctx, "LONGLONG") ||
1080        !add_max_definition<boost::ulong_long_type>(ctx, "ULONGLONG") ||
1081#endif
1082        !add_max_definition<long>(ctx, "LONG") ||
1083        !add_max_definition<unsigned long>(ctx, "ULONG"))
1084    {
1085        std::cerr << "testwave: failed to add a predefined macro (MAX)." 
1086                  << std::endl;
1087    }
1088
1089#if BOOST_WAVE_USE_STRICT_LEXER != 0
1090    return add_strict_lexer_definition(ctx);
1091#else
1092    return true;
1093#endif
1094}
1095
1096///////////////////////////////////////////////////////////////////////////////
1097//
1098//  Preprocess the given input data and return the generated output through
1099//  the parameter 'result'.
1100//
1101///////////////////////////////////////////////////////////////////////////////
1102bool 
1103testwave_app::preprocess_file(std::string filename, std::string const& instr, 
1104    std::string& result, std::string& error, bool single_line)
1105{
1106//  create the wave::context object and initialize it from the file to
1107//  preprocess (may contain options inside of special comments)
1108    typedef boost::wave::cpplexer::lex_token<> token_type;
1109    typedef boost::wave::cpplexer::lex_iterator<token_type> lexer_type;
1110    typedef boost::wave::context<std::string::const_iterator, lexer_type> 
1111        context_type;
1112
1113    if (9 == debuglevel) {
1114        std::cerr << "preprocess_file: preprocessing input file: " << filename
1115                  << std::endl;
1116    }
1117
1118    try {   
1119    //  create preprocessing context
1120        context_type ctx(instr.begin(), instr.end(), filename.c_str());
1121
1122    //  initialize the context from the options given on the command line
1123        if (!initialise_options(ctx, global_vm, single_line))
1124            return false;
1125
1126    //  extract the options from the input data and initialize the context
1127        if (!extract_options(filename, instr, ctx, single_line))
1128            return false;
1129
1130    //  add special predefined macros
1131        if (!add_predefined_macros(ctx))
1132            return false;
1133       
1134    //  preprocess the input, loop over all generated tokens collecting the
1135    //  generated text
1136        context_type::iterator_type end = ctx.end();
1137        for (context_type::iterator_type it = ctx.begin(); it != end; ++it) 
1138        {
1139            using namespace boost::wave;
1140           
1141            if (T_PP_LINE == token_id(*it)) {
1142            // special handling of the whole #line directive is required to
1143            // allow correct file name matching
1144                if (!handle_line_directive(it, end, result))
1145                    return false;   // unexpected eof
1146            }
1147            else {
1148                // add the value of the current token
1149                result = result + (*it).get_value().c_str(); 
1150            }
1151        }
1152        error.clear();
1153    }
1154    catch (boost::wave::cpplexer::lexing_exception const& e) {
1155    // some lexer error
1156        BOOST_WAVETEST_OSSTREAM strm;
1157        std::string filename = e.file_name();
1158        strm
1159            << handle_filepath(filename) << "(" << e.line_no() << "): "
1160            << e.description() << std::endl;
1161           
1162        error = BOOST_WAVETEST_GETSTRING(strm);
1163        return false;
1164    }
1165    catch (boost::wave::cpp_exception const& e) {
1166    // some preprocessing error
1167        BOOST_WAVETEST_OSSTREAM strm;
1168        std::string filename = e.file_name();
1169        strm
1170            << handle_filepath(filename) << "(" << e.line_no() << "): "
1171            << e.description() << std::endl;
1172           
1173        error = BOOST_WAVETEST_GETSTRING(strm);
1174        return false;
1175    }
1176   
1177    if (9 == debuglevel) {
1178        std::cerr << "preprocess_file: succeeded to preprocess input file: " 
1179                  << filename << std::endl;
1180    }
1181
1182    return true;
1183}
1184
Note: See TracBrowser for help on using the repository browser.