cpp.cpp 58 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508
  1. /*=============================================================================
  2. Boost.Wave: A Standard compliant C++ preprocessor library
  3. http://www.boost.org/
  4. Copyright (c) 2001-2012 Hartmut Kaiser. Distributed under the Boost
  5. Software License, Version 1.0. (See accompanying file
  6. LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  7. =============================================================================*/
  8. #define BOOST_WAVE_SERIALIZATION 0 // enable serialization
  9. #define BOOST_WAVE_BINARY_SERIALIZATION 0 // use binary archives
  10. #define BOOST_WAVE_XML_SERIALIZATION 1 // use XML archives
  11. #include "cpp.hpp" // global configuration
  12. ///////////////////////////////////////////////////////////////////////////////
  13. // Include additional Boost libraries
  14. #include <boost/filesystem/path.hpp>
  15. #include <boost/filesystem/convenience.hpp>
  16. #include <boost/filesystem/fstream.hpp>
  17. #include <boost/timer.hpp>
  18. #include <boost/any.hpp>
  19. #include <boost/algorithm/cxx11/any_of.hpp>
  20. #include <boost/algorithm/string/join.hpp>
  21. #include <boost/range/algorithm/find.hpp>
  22. #include <boost/range/end.hpp>
  23. #include <boost/foreach.hpp>
  24. ///////////////////////////////////////////////////////////////////////////////
  25. // Include Wave itself
  26. #include <boost/wave.hpp>
  27. ///////////////////////////////////////////////////////////////////////////////
  28. // Include the lexer related stuff
  29. #include <boost/wave/cpplexer/cpp_lex_token.hpp> // token type
  30. #include <boost/wave/cpplexer/cpp_lex_iterator.hpp> // lexer type
  31. ///////////////////////////////////////////////////////////////////////////////
  32. // Include serialization support, if requested
  33. #if BOOST_WAVE_SERIALIZATION != 0
  34. #include <boost/serialization/serialization.hpp>
  35. #if BOOST_WAVE_BINARY_SERIALIZATION != 0
  36. #include <boost/archive/binary_iarchive.hpp>
  37. #include <boost/archive/binary_oarchive.hpp>
  38. typedef boost::archive::binary_iarchive iarchive;
  39. typedef boost::archive::binary_oarchive oarchive;
  40. #elif BOOST_WAVE_XML_SERIALIZATION != 0
  41. #include <boost/archive/xml_iarchive.hpp>
  42. #include <boost/archive/xml_oarchive.hpp>
  43. typedef boost::archive::xml_iarchive iarchive;
  44. typedef boost::archive::xml_oarchive oarchive;
  45. #else
  46. #include <boost/archive/text_iarchive.hpp>
  47. #include <boost/archive/text_oarchive.hpp>
  48. typedef boost::archive::text_iarchive iarchive;
  49. typedef boost::archive::text_oarchive oarchive;
  50. #endif
  51. #endif
  52. ///////////////////////////////////////////////////////////////////////////////
  53. // Include the context policies to use
  54. #include "trace_macro_expansion.hpp"
  55. ///////////////////////////////////////////////////////////////////////////////
  56. // Include lexer specifics, import lexer names
  57. #if BOOST_WAVE_SEPARATE_LEXER_INSTANTIATION == 0
  58. #include <boost/wave/cpplexer/re2clex/cpp_re2c_lexer.hpp>
  59. #endif
  60. ///////////////////////////////////////////////////////////////////////////////
  61. // Include the grammar definitions, if these shouldn't be compiled separately
  62. // (ATTENTION: _very_ large compilation times!)
  63. #if BOOST_WAVE_SEPARATE_GRAMMAR_INSTANTIATION == 0
  64. #include <boost/wave/grammars/cpp_intlit_grammar.hpp>
  65. #include <boost/wave/grammars/cpp_chlit_grammar.hpp>
  66. #include <boost/wave/grammars/cpp_grammar.hpp>
  67. #include <boost/wave/grammars/cpp_expression_grammar.hpp>
  68. #include <boost/wave/grammars/cpp_predef_macros_grammar.hpp>
  69. #include <boost/wave/grammars/cpp_defined_grammar.hpp>
  70. #endif
  71. ///////////////////////////////////////////////////////////////////////////////
  72. // Import required names
  73. using namespace boost::spirit::classic;
  74. using std::pair;
  75. using std::vector;
  76. using std::getline;
  77. using boost::filesystem::ofstream;
  78. using boost::filesystem::ifstream;
  79. using std::cout;
  80. using std::cerr;
  81. using std::endl;
  82. using std::ostream;
  83. using std::istreambuf_iterator;
  84. ///////////////////////////////////////////////////////////////////////////////
  85. //
  86. // This application uses the lex_iterator and lex_token types predefined
  87. // with the Wave library, but it is possible to use your own types.
  88. //
  89. // You may want to have a look at the other samples to see how this is
  90. // possible to achieve.
  91. typedef boost::wave::cpplexer::lex_token<> token_type;
  92. typedef boost::wave::cpplexer::lex_iterator<token_type>
  93. lex_iterator_type;
  94. // The C++ preprocessor iterators shouldn't be constructed directly. They
  95. // are to be generated through a boost::wave::context<> object. This
  96. // boost::wave::context object is additionally to be used to initialize and
  97. // define different parameters of the actual preprocessing.
  98. typedef boost::wave::context<
  99. std::string::iterator, lex_iterator_type,
  100. boost::wave::iteration_context_policies::load_file_to_string,
  101. trace_macro_expansion<token_type> >
  102. context_type;
  103. ///////////////////////////////////////////////////////////////////////////////
  104. // print the current version
  105. std::string get_version()
  106. {
  107. std::string version (context_type::get_version_string());
  108. version = version.substr(1, version.size()-2); // strip quotes
  109. version += std::string(" (" CPP_VERSION_DATE_STR ")"); // add date
  110. return version;
  111. }
  112. ///////////////////////////////////////////////////////////////////////////////
  113. // print the current version for interactive sessions
  114. int print_interactive_version()
  115. {
  116. cout << "Wave: A Standard conformant C++ preprocessor based on the Boost.Wave library" << endl;
  117. cout << "Version: " << get_version() << endl;
  118. return 0;
  119. }
  120. ///////////////////////////////////////////////////////////////////////////////
  121. // print the copyright statement
  122. int print_copyright()
  123. {
  124. char const *copyright[] = {
  125. "",
  126. "Wave: A Standard conformant C++ preprocessor based on the Boost.Wave library",
  127. "http://www.boost.org/",
  128. "",
  129. "Copyright (c) 2001-2012 Hartmut Kaiser, Distributed under the Boost",
  130. "Software License, Version 1.0. (See accompanying file",
  131. "LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)",
  132. 0
  133. };
  134. for (int i = 0; 0 != copyright[i]; ++i)
  135. cout << copyright[i] << endl;
  136. return 0; // exit app
  137. }
  138. ///////////////////////////////////////////////////////////////////////////////
  139. // forward declarations only
  140. namespace cmd_line_utils
  141. {
  142. class include_paths;
  143. }
  144. namespace boost { namespace program_options {
  145. void validate(boost::any &v, std::vector<std::string> const &s,
  146. cmd_line_utils::include_paths *, long);
  147. }} // boost::program_options
  148. ///////////////////////////////////////////////////////////////////////////////
  149. #include <boost/program_options.hpp>
  150. namespace po = boost::program_options;
  151. namespace fs = boost::filesystem;
  152. ///////////////////////////////////////////////////////////////////////////////
  153. namespace cmd_line_utils {
  154. // Additional command line parser which interprets '@something' as an
  155. // option "config-file" with the value "something".
  156. inline pair<std::string, std::string>
  157. at_option_parser(std::string const&s)
  158. {
  159. if ('@' == s[0])
  160. return std::make_pair(std::string("config-file"), s.substr(1));
  161. else
  162. return pair<std::string, std::string>();
  163. }
  164. // class, which keeps include file information read from the command line
  165. class include_paths {
  166. public:
  167. include_paths() : seen_separator(false) {}
  168. vector<std::string> paths; // stores user paths
  169. vector<std::string> syspaths; // stores system paths
  170. bool seen_separator; // command line contains a '-I-' option
  171. // Function which validates additional tokens from command line.
  172. static void
  173. validate(boost::any &v, vector<std::string> const &tokens)
  174. {
  175. if (v.empty())
  176. v = boost::any(include_paths());
  177. include_paths *p = boost::any_cast<include_paths>(&v);
  178. BOOST_ASSERT(p);
  179. // Assume only one path per '-I' occurrence.
  180. std::string const& t = po::validators::get_single_string(tokens);
  181. if (t == "-") {
  182. // found -I- option, so switch behaviour
  183. p->seen_separator = true;
  184. }
  185. else if (p->seen_separator) {
  186. // store this path as a system path
  187. p->syspaths.push_back(t);
  188. }
  189. else {
  190. // store this path as an user path
  191. p->paths.push_back(t);
  192. }
  193. }
  194. };
  195. // Read all options from a given config file, parse and add them to the
  196. // given variables_map
  197. bool read_config_file_options(std::string const &filename,
  198. po::options_description const &desc, po::variables_map &vm,
  199. bool may_fail = false)
  200. {
  201. ifstream ifs(filename.c_str());
  202. if (!ifs.is_open()) {
  203. if (!may_fail) {
  204. cerr << filename
  205. << ": command line warning: config file not found"
  206. << endl;
  207. }
  208. return false;
  209. }
  210. vector<std::string> options;
  211. std::string line;
  212. while (std::getline(ifs, line)) {
  213. // skip empty lines
  214. std::string::size_type pos = line.find_first_not_of(" \t");
  215. if (pos == std::string::npos)
  216. continue;
  217. // skip comment lines
  218. if ('#' != line[pos]) {
  219. // strip leading and trailing whitespace
  220. std::string::size_type endpos = line.find_last_not_of(" \t");
  221. BOOST_ASSERT(endpos != std::string::npos);
  222. options.push_back(line.substr(pos, endpos-pos+1));
  223. }
  224. }
  225. if (options.size() > 0) {
  226. using namespace boost::program_options::command_line_style;
  227. po::store(po::command_line_parser(options)
  228. .options(desc).style(unix_style).run(), vm);
  229. po::notify(vm);
  230. }
  231. return true;
  232. }
  233. // predicate to extract all positional arguments from the command line
  234. struct is_argument {
  235. bool operator()(po::option const &opt)
  236. {
  237. return (opt.position_key == -1) ? true : false;
  238. }
  239. };
  240. // trim quotes from path names, if any
  241. std::string trim_quotes(std::string const& file)
  242. {
  243. if (('"' == file[0] || '\'' == file[0]) && file[0] == file[file.size()-1])
  244. {
  245. return file.substr(1, file.size()-2);
  246. }
  247. return file;
  248. }
  249. ///////////////////////////////////////////////////////////////////////////////
  250. }
  251. ///////////////////////////////////////////////////////////////////////////////
  252. //
  253. // Special validator overload, which allows to handle the -I- syntax for
  254. // switching the semantics of an -I option.
  255. //
  256. ///////////////////////////////////////////////////////////////////////////////
  257. namespace boost { namespace program_options {
  258. void validate(boost::any &v, std::vector<std::string> const &s,
  259. cmd_line_utils::include_paths *, long)
  260. {
  261. cmd_line_utils::include_paths::validate(v, s);
  262. }
  263. }} // namespace boost::program_options
  264. ///////////////////////////////////////////////////////////////////////////////
  265. namespace {
  266. class auto_stop_watch : public stop_watch
  267. {
  268. public:
  269. auto_stop_watch(std::ostream &outstrm_)
  270. : print_time(false), outstrm(outstrm_)
  271. {
  272. }
  273. ~auto_stop_watch()
  274. {
  275. if (print_time) {
  276. outstrm << "Elapsed time: "
  277. << this->format_elapsed_time()
  278. << std::endl;
  279. }
  280. }
  281. void set_print_time(bool print_time_)
  282. {
  283. print_time = print_time_;
  284. }
  285. private:
  286. bool print_time;
  287. std::ostream &outstrm;
  288. };
  289. ///////////////////////////////////////////////////////////////////////////
  290. inline std::string
  291. report_iostate_error(std::ios::iostate state)
  292. {
  293. BOOST_ASSERT(state & (std::ios::badbit | std::ios::failbit | std::ios::eofbit));
  294. std::string result;
  295. if (state & std::ios::badbit) {
  296. result += " the reported problem was: "
  297. "loss of integrity of the stream buffer\n";
  298. }
  299. if (state & std::ios::failbit) {
  300. result += " the reported problem was: "
  301. "an operation was not processed correctly\n";
  302. }
  303. if (state & std::ios::eofbit) {
  304. result += " the reported problem was: "
  305. "end-of-file while writing to the stream\n";
  306. }
  307. return result;
  308. }
  309. ///////////////////////////////////////////////////////////////////////////
  310. // Retrieve the position of a macro definition
  311. template <typename Context>
  312. inline bool
  313. get_macro_position(Context &ctx,
  314. typename Context::token_type::string_type const& name,
  315. typename Context::position_type &pos)
  316. {
  317. bool has_parameters = false;
  318. bool is_predefined = false;
  319. std::vector<typename Context::token_type> parameters;
  320. typename Context::token_sequence_type definition;
  321. return ctx.get_macro_definition(name, has_parameters, is_predefined,
  322. pos, parameters, definition);
  323. }
  324. ///////////////////////////////////////////////////////////////////////////
  325. // Generate some meaningful error messages
  326. template <typename Exception>
  327. inline int
  328. report_error_message(Exception const &e, bool treat_warnings_as_error)
  329. {
  330. // default error reporting
  331. cerr
  332. << e.file_name() << ":" << e.line_no() << ":" << e.column_no()
  333. << ": " << e.description() << endl;
  334. // errors count as one
  335. return (treat_warnings_as_error ||
  336. e.get_severity() == boost::wave::util::severity_error ||
  337. e.get_severity() == boost::wave::util::severity_fatal) ? 1 : 0;
  338. }
  339. template <typename Context>
  340. inline int
  341. report_error_message(Context &ctx, boost::wave::cpp_exception const &e,
  342. bool treat_warnings_as_error)
  343. {
  344. // default error reporting
  345. int result = report_error_message(e, treat_warnings_as_error);
  346. using boost::wave::preprocess_exception;
  347. switch(e.get_errorcode()) {
  348. case preprocess_exception::macro_redefinition:
  349. {
  350. // report the point of the initial macro definition
  351. typename Context::position_type pos;
  352. if (get_macro_position(ctx, e.get_related_name(), pos)) {
  353. cerr
  354. << pos << ": "
  355. << preprocess_exception::severity_text(e.get_severity())
  356. << ": this is the location of the previous definition."
  357. << endl;
  358. }
  359. else {
  360. cerr
  361. << e.file_name() << ":" << e.line_no() << ":"
  362. << e.column_no() << ": "
  363. << preprocess_exception::severity_text(e.get_severity())
  364. << ": not able to retrieve the location of the previous "
  365. << "definition." << endl;
  366. }
  367. }
  368. break;
  369. default:
  370. break;
  371. }
  372. return result;
  373. }
  374. ///////////////////////////////////////////////////////////////////////////
  375. // Read one logical line of text
  376. inline bool
  377. read_a_line (std::istream &instream, std::string &instring)
  378. {
  379. bool eol = true;
  380. do {
  381. std::string line;
  382. std::getline(instream, line);
  383. if (instream.rdstate() & std::ios::failbit)
  384. return false; // nothing to do
  385. eol = true;
  386. if (line.find_last_of('\\') == line.size()-1)
  387. eol = false;
  388. instring += line + '\n';
  389. } while (!eol);
  390. return true;
  391. }
  392. ///////////////////////////////////////////////////////////////////////////
  393. // Load and save the internal tables of the wave::context object
  394. template <typename Context>
  395. inline void
  396. load_state(po::variables_map const &vm, Context &ctx)
  397. {
  398. #if BOOST_WAVE_SERIALIZATION != 0
  399. try {
  400. if (vm.count("state") > 0) {
  401. fs::path state_file (
  402. boost::wave::util::create_path(vm["state"].as<std::string>()));
  403. if (state_file == "-")
  404. state_file = boost::wave::util::create_path("wave.state");
  405. std::ios::openmode mode = std::ios::in;
  406. #if BOOST_WAVE_BINARY_SERIALIZATION != 0
  407. mode = (std::ios::openmode)(mode | std::ios::binary);
  408. #endif
  409. ifstream ifs (state_file.string().c_str(), mode);
  410. if (ifs.is_open()) {
  411. using namespace boost::serialization;
  412. iarchive ia(ifs);
  413. std::string version;
  414. ia >> make_nvp("version", version); // load version
  415. if (version == CPP_VERSION_FULL_STR)
  416. ia >> make_nvp("state", ctx); // load the internal tables from disc
  417. else {
  418. cerr << "wave: detected version mismatch while loading state, state was not loaded." << endl;
  419. cerr << " loaded version: " << version << endl;
  420. cerr << " expected version: " << CPP_VERSION_FULL_STR << endl;
  421. }
  422. }
  423. }
  424. }
  425. catch (boost::archive::archive_exception const& e) {
  426. cerr << "wave: error while loading state: "
  427. << e.what() << endl;
  428. }
  429. catch (boost::wave::preprocess_exception const& e) {
  430. cerr << "wave: error while loading state: "
  431. << e.description() << endl;
  432. }
  433. #endif
  434. }
  435. template <typename Context>
  436. inline void
  437. save_state(po::variables_map const &vm, Context const &ctx)
  438. {
  439. #if BOOST_WAVE_SERIALIZATION != 0
  440. try {
  441. if (vm.count("state") > 0) {
  442. fs::path state_file (boost::wave::util::create_path(
  443. vm["state"].as<std::string>()));
  444. if (state_file == "-")
  445. state_file = boost::wave::util::create_path("wave.state");
  446. std::ios::openmode mode = std::ios::out;
  447. #if BOOST_WAVE_BINARY_SERIALIZATION != 0
  448. mode = (std::ios::openmode)(mode | std::ios::binary);
  449. #endif
  450. ofstream ofs(state_file.string().c_str(), mode);
  451. if (!ofs.is_open()) {
  452. cerr << "wave: could not open state file for writing: "
  453. << state_file.string() << endl;
  454. // this is non-fatal
  455. }
  456. else {
  457. using namespace boost::serialization;
  458. oarchive oa(ofs);
  459. std::string version(CPP_VERSION_FULL_STR);
  460. oa << make_nvp("version", version); // write version
  461. oa << make_nvp("state", ctx); // write the internal tables to disc
  462. }
  463. }
  464. }
  465. catch (boost::archive::archive_exception const& e) {
  466. cerr << "wave: error while writing state: "
  467. << e.what() << endl;
  468. }
  469. #endif
  470. }
  471. ///////////////////////////////////////////////////////////////////////////
  472. // list all defined macros
  473. bool list_macro_names(context_type const& ctx, std::string filename)
  474. {
  475. // open file for macro names listing
  476. ofstream macronames_out;
  477. fs::path macronames_file (boost::wave::util::create_path(filename));
  478. if (macronames_file != "-") {
  479. macronames_file = boost::wave::util::complete_path(macronames_file);
  480. boost::wave::util::create_directories(
  481. boost::wave::util::branch_path(macronames_file));
  482. macronames_out.open(macronames_file.string().c_str());
  483. if (!macronames_out.is_open()) {
  484. cerr << "wave: could not open file for macro name listing: "
  485. << macronames_file.string() << endl;
  486. return false;
  487. }
  488. }
  489. else {
  490. macronames_out.copyfmt(cout);
  491. macronames_out.clear(cout.rdstate());
  492. static_cast<std::basic_ios<char> &>(macronames_out).rdbuf(cout.rdbuf());
  493. }
  494. // simply list all defined macros and its definitions
  495. typedef context_type::const_name_iterator name_iterator;
  496. name_iterator end = ctx.macro_names_end();
  497. for (name_iterator it = ctx.macro_names_begin(); it != end; ++it)
  498. {
  499. typedef std::vector<context_type::token_type> parameters_type;
  500. bool has_pars = false;
  501. bool predef = false;
  502. context_type::position_type pos;
  503. parameters_type pars;
  504. context_type::token_sequence_type def;
  505. if (ctx.get_macro_definition(*it, has_pars, predef, pos, pars, def))
  506. {
  507. macronames_out << (predef ? "-P" : "-D") << *it;
  508. if (has_pars) {
  509. // list the parameter names for function style macros
  510. macronames_out << "(";
  511. parameters_type::const_iterator pend = pars.end();
  512. for (parameters_type::const_iterator pit = pars.begin();
  513. pit != pend; /**/)
  514. {
  515. macronames_out << (*pit).get_value();
  516. if (++pit != pend)
  517. macronames_out << ", ";
  518. }
  519. macronames_out << ")";
  520. }
  521. macronames_out << "=";
  522. // print the macro definition
  523. context_type::token_sequence_type::const_iterator dend = def.end();
  524. for (context_type::token_sequence_type::const_iterator dit = def.begin();
  525. dit != dend; ++dit)
  526. {
  527. macronames_out << (*dit).get_value();
  528. }
  529. macronames_out << std::endl;
  530. }
  531. }
  532. return true;
  533. }
  534. ///////////////////////////////////////////////////////////////////////////
  535. // list macro invocation counts
  536. bool list_macro_counts(context_type const& ctx, std::string filename)
  537. {
  538. // open file for macro invocation count listing
  539. ofstream macrocounts_out;
  540. fs::path macrocounts_file (boost::wave::util::create_path(filename));
  541. if (macrocounts_file != "-") {
  542. macrocounts_file = boost::wave::util::complete_path(macrocounts_file);
  543. boost::wave::util::create_directories(
  544. boost::wave::util::branch_path(macrocounts_file));
  545. macrocounts_out.open(macrocounts_file.string().c_str());
  546. if (!macrocounts_out.is_open()) {
  547. cerr << "wave: could not open file for macro invocation count listing: "
  548. << macrocounts_file.string() << endl;
  549. return false;
  550. }
  551. }
  552. else {
  553. macrocounts_out.copyfmt(cout);
  554. macrocounts_out.clear(cout.rdstate());
  555. static_cast<std::basic_ios<char> &>(macrocounts_out).rdbuf(cout.rdbuf());
  556. }
  557. // list all expanded macro names and their counts in alphabetical order
  558. std::map<std::string, std::size_t> const& counts =
  559. ctx.get_hooks().get_macro_counts();
  560. typedef std::map<std::string, std::size_t>::const_iterator iterator;
  561. iterator end = counts.end();
  562. for (iterator it = counts.begin(); it != end; ++it)
  563. macrocounts_out << (*it).first << "," << (*it).second << std::endl;
  564. return true;
  565. }
  566. ///////////////////////////////////////////////////////////////////////////
  567. // read all of a file into a string
  568. std::string read_entire_file(std::istream& instream)
  569. {
  570. std::string content;
  571. instream.unsetf(std::ios::skipws);
  572. #if defined(BOOST_NO_TEMPLATED_ITERATOR_CONSTRUCTORS)
  573. // this is known to be very slow for large files on some systems
  574. copy (std::istream_iterator<char>(instream),
  575. std::istream_iterator<char>(),
  576. std::inserter(content, content.end()));
  577. #else
  578. content = std::string(std::istreambuf_iterator<char>(instream.rdbuf()),
  579. std::istreambuf_iterator<char>());
  580. #endif
  581. return content;
  582. }
  583. } // anonymous namespace
  584. ///////////////////////////////////////////////////////////////////////////////
  585. // do the actual preprocessing
  586. int
  587. do_actual_work (std::string file_name, std::istream &instream,
  588. po::variables_map const &vm, bool input_is_stdin)
  589. {
  590. // current file position is saved for exception handling
  591. boost::wave::util::file_position_type current_position;
  592. auto_stop_watch elapsed_time(cerr);
  593. int error_count = 0;
  594. const bool treat_warnings_as_error = vm.count("warning") &&
  595. boost::algorithm::any_of_equal(
  596. vm["warning"].as<std::vector<std::string> >(), "error");
  597. try {
  598. // process the given file
  599. std::string instring;
  600. instream.unsetf(std::ios::skipws);
  601. if (!input_is_stdin)
  602. instring = read_entire_file(instream);
  603. // The preprocessing of the input stream is done on the fly behind the
  604. // scenes during iteration over the context_type::iterator_type stream.
  605. ofstream output;
  606. ofstream traceout;
  607. ofstream includelistout;
  608. ofstream listguardsout;
  609. trace_flags enable_trace = trace_nothing;
  610. if (vm.count("traceto")) {
  611. // try to open the file, where to put the trace output
  612. fs::path trace_file (boost::wave::util::create_path(
  613. vm["traceto"].as<std::string>()));
  614. if (trace_file != "-") {
  615. boost::wave::util::create_directories(
  616. boost::wave::util::branch_path(trace_file));
  617. traceout.open(trace_file.string().c_str());
  618. if (!traceout.is_open()) {
  619. cerr << "wave: could not open trace file: " << trace_file
  620. << endl;
  621. return -1;
  622. }
  623. }
  624. enable_trace = trace_macros;
  625. }
  626. if ((enable_trace & trace_macros) && !traceout.is_open()) {
  627. // by default trace to std::cerr
  628. traceout.copyfmt(cerr);
  629. traceout.clear(cerr.rdstate());
  630. static_cast<std::basic_ios<char> &>(traceout).rdbuf(cerr.rdbuf());
  631. }
  632. // Open the stream where to output the list of included file names
  633. if (vm.count("listincludes")) {
  634. // try to open the file, where to put the include list
  635. fs::path includes_file(boost::wave::util::create_path(
  636. vm["listincludes"].as<std::string>()));
  637. if (includes_file != "-") {
  638. boost::wave::util::create_directories(
  639. boost::wave::util::branch_path(includes_file));
  640. includelistout.open(includes_file.string().c_str());
  641. if (!includelistout.is_open()) {
  642. cerr << "wave: could not open include list file: "
  643. << includes_file.string() << endl;
  644. return -1;
  645. }
  646. }
  647. enable_trace = trace_flags(enable_trace | trace_includes);
  648. }
  649. if ((enable_trace & trace_includes) && !includelistout.is_open()) {
  650. // by default list included names to std::cout
  651. includelistout.copyfmt(cout);
  652. includelistout.clear(cout.rdstate());
  653. static_cast<std::basic_ios<char> &>(includelistout).
  654. rdbuf(cout.rdbuf());
  655. }
  656. // Open the stream where to output the list of included file names
  657. if (vm.count("listguards")) {
  658. // try to open the file, where to put the include list
  659. fs::path listguards_file(boost::wave::util::create_path(
  660. vm["listguards"].as<std::string>()));
  661. if (listguards_file != "-") {
  662. boost::wave::util::create_directories(
  663. boost::wave::util::branch_path(listguards_file));
  664. listguardsout.open(listguards_file.string().c_str());
  665. if (!listguardsout.is_open()) {
  666. cerr << "wave: could not open include guard list file: "
  667. << listguards_file.string() << endl;
  668. return -1;
  669. }
  670. }
  671. enable_trace = trace_flags(enable_trace | trace_guards);
  672. }
  673. if ((enable_trace & trace_guards) && !listguardsout.is_open()) {
  674. // by default list included names to std::cout
  675. listguardsout.copyfmt(cout);
  676. listguardsout.clear(cout.rdstate());
  677. static_cast<std::basic_ios<char> &>(listguardsout).
  678. rdbuf(cout.rdbuf());
  679. }
  680. // enable preserving comments mode
  681. bool preserve_comments = false;
  682. bool preserve_whitespace = false;
  683. bool preserve_bol_whitespace = false;
  684. if (vm.count("preserve")) {
  685. int preserve = vm["preserve"].as<int>();
  686. switch(preserve) {
  687. case 0: break; // preserve no whitespace
  688. case 3: // preserve all whitespace
  689. preserve_whitespace = true;
  690. preserve_comments = true;
  691. preserve_bol_whitespace = true;
  692. break;
  693. case 2: // preserve comments and BOL whitespace only
  694. preserve_comments = true;
  695. preserve_bol_whitespace = true;
  696. break;
  697. case 1: // preserve BOL whitespace only
  698. preserve_bol_whitespace = true;
  699. break;
  700. default:
  701. cerr << "wave: bogus preserve whitespace option value: "
  702. << preserve << ", should be 0, 1, 2, or 3" << endl;
  703. return -1;
  704. }
  705. }
  706. // Since the #pragma wave system() directive may cause a potential security
  707. // threat, it has to be enabled explicitly by --extended or -x
  708. bool enable_system_command = false;
  709. if (vm.count("extended"))
  710. enable_system_command = true;
  711. // This this the central piece of the Wave library, it provides you with
  712. // the iterators to get the preprocessed tokens and allows to configure
  713. // the preprocessing stage in advance.
  714. bool allow_output = true; // will be manipulated from inside the hooks object
  715. std::string default_outfile; // will be used from inside the hooks object
  716. trace_macro_expansion<token_type> hooks(preserve_whitespace,
  717. preserve_bol_whitespace, output, traceout, includelistout,
  718. listguardsout, enable_trace, enable_system_command, allow_output,
  719. default_outfile);
  720. // enable macro invocation count, if appropriate
  721. if (vm.count("macrocounts"))
  722. hooks.enable_macro_counting();
  723. // check, if we have a license file to prepend
  724. std::string license;
  725. if (vm.count ("license")) {
  726. // try to open the file, where to put the preprocessed output
  727. std::string license_file(vm["license"].as<std::string>());
  728. ifstream license_stream(license_file.c_str());
  729. if (!license_stream.is_open()) {
  730. cerr << "wave: could not open specified license file: "
  731. << license_file << endl;
  732. return -1;
  733. }
  734. license = read_entire_file(license_stream);
  735. hooks.set_license_info(license);
  736. }
  737. context_type ctx (instring.begin(), instring.end(), file_name.c_str(), hooks);
  738. #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
  739. // enable C99 mode, if appropriate (implies variadics)
  740. if (vm.count("c99")) {
  741. #if BOOST_WAVE_SUPPORT_CPP0X != 0
  742. if (vm.count("c++11")) {
  743. cerr << "wave: multiple language options specified: --c99 "
  744. "and --c++11" << endl;
  745. return -1;
  746. }
  747. #endif
  748. ctx.set_language(
  749. boost::wave::language_support(
  750. boost::wave::support_c99
  751. | boost::wave::support_option_convert_trigraphs
  752. | boost::wave::support_option_emit_line_directives
  753. #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
  754. | boost::wave::support_option_include_guard_detection
  755. #endif
  756. #if BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES != 0
  757. | boost::wave::support_option_emit_pragma_directives
  758. #endif
  759. | boost::wave::support_option_insert_whitespace
  760. ));
  761. }
  762. else if (vm.count("variadics")) {
  763. // enable variadics and placemarkers, if appropriate
  764. ctx.set_language(boost::wave::enable_variadics(ctx.get_language()));
  765. }
  766. #endif // BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
  767. #if BOOST_WAVE_SUPPORT_CPP0X != 0
  768. if (vm.count("c++11")) {
  769. if (vm.count("c99")) {
  770. cerr << "wave: multiple language options specified: --c99 "
  771. "and --c++11" << endl;
  772. return -1;
  773. }
  774. ctx.set_language(
  775. boost::wave::language_support(
  776. boost::wave::support_cpp0x
  777. | boost::wave::support_option_convert_trigraphs
  778. | boost::wave::support_option_long_long
  779. | boost::wave::support_option_emit_line_directives
  780. #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
  781. | boost::wave::support_option_include_guard_detection
  782. #endif
  783. #if BOOST_WAVE_EMIT_PRAGMA_DIRECTIVES != 0
  784. | boost::wave::support_option_emit_pragma_directives
  785. #endif
  786. | boost::wave::support_option_insert_whitespace
  787. ));
  788. }
  789. #endif // BOOST_WAVE_SUPPORT_CPP0X != 0
  790. // enable long long support, if appropriate
  791. if (vm.count("long_long")) {
  792. ctx.set_language(
  793. boost::wave::enable_long_long(ctx.get_language()));
  794. }
  795. #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
  796. // disable include guard detection
  797. if (vm.count("noguard")) {
  798. ctx.set_language(
  799. boost::wave::enable_include_guard_detection(
  800. ctx.get_language(), false));
  801. }
  802. #endif
  803. // enable preserving comments mode
  804. if (preserve_comments) {
  805. ctx.set_language(
  806. boost::wave::enable_preserve_comments(ctx.get_language()));
  807. }
  808. // control the generation of #line directives
  809. if (vm.count("line")) {
  810. int lineopt = vm["line"].as<int>();
  811. if (0 != lineopt && 1 != lineopt && 2 != lineopt) {
  812. cerr << "wave: bogus value for --line command line option: "
  813. << lineopt << endl;
  814. return -1;
  815. }
  816. ctx.set_language(
  817. boost::wave::enable_emit_line_directives(ctx.get_language(),
  818. lineopt != 0));
  819. if (2 == lineopt)
  820. ctx.get_hooks().enable_relative_names_in_line_directives(true);
  821. }
  822. // control whether whitespace should be inserted to disambiguate output
  823. if (vm.count("disambiguate")) {
  824. int disambiguateopt = vm["disambiguate"].as<int>();
  825. if (0 != disambiguateopt && 1 != disambiguateopt) {
  826. cerr << "wave: bogus value for --disambiguate command line option: "
  827. << disambiguateopt << endl;
  828. return -1;
  829. }
  830. ctx.set_language(
  831. boost::wave::enable_insert_whitespace(ctx.get_language(),
  832. disambiguateopt != 0));
  833. }
  834. // add include directories to the system include search paths
  835. if (vm.count("sysinclude")) {
  836. vector<std::string> syspaths = vm["sysinclude"].as<vector<std::string> >();
  837. vector<std::string>::const_iterator end = syspaths.end();
  838. for (vector<std::string>::const_iterator cit = syspaths.begin();
  839. cit != end; ++cit)
  840. {
  841. ctx.add_sysinclude_path(cmd_line_utils::trim_quotes(*cit).c_str());
  842. }
  843. }
  844. // add include directories to the include search paths
  845. if (vm.count("include")) {
  846. cmd_line_utils::include_paths const &ip =
  847. vm["include"].as<cmd_line_utils::include_paths>();
  848. vector<std::string>::const_iterator end = ip.paths.end();
  849. for (vector<std::string>::const_iterator cit = ip.paths.begin();
  850. cit != end; ++cit)
  851. {
  852. ctx.add_include_path(cmd_line_utils::trim_quotes(*cit).c_str());
  853. }
  854. // if -I- was given on the command line, this has to be propagated
  855. if (ip.seen_separator)
  856. ctx.set_sysinclude_delimiter();
  857. // add system include directories to the include path
  858. vector<std::string>::const_iterator sysend = ip.syspaths.end();
  859. for (vector<std::string>::const_iterator syscit = ip.syspaths.begin();
  860. syscit != sysend; ++syscit)
  861. {
  862. ctx.add_sysinclude_path(cmd_line_utils::trim_quotes(*syscit).c_str());
  863. }
  864. }
  865. // add additional defined macros
  866. if (vm.count("define")) {
  867. vector<std::string> const &macros = vm["define"].as<vector<std::string> >();
  868. vector<std::string>::const_iterator end = macros.end();
  869. for (vector<std::string>::const_iterator cit = macros.begin();
  870. cit != end; ++cit)
  871. {
  872. ctx.add_macro_definition(*cit);
  873. }
  874. }
  875. // add additional predefined macros
  876. if (vm.count("predefine")) {
  877. vector<std::string> const &predefmacros =
  878. vm["predefine"].as<vector<std::string> >();
  879. vector<std::string>::const_iterator end = predefmacros.end();
  880. for (vector<std::string>::const_iterator cit = predefmacros.begin();
  881. cit != end; ++cit)
  882. {
  883. ctx.add_macro_definition(*cit, true);
  884. }
  885. }
  886. // undefine specified macros
  887. if (vm.count("undefine")) {
  888. vector<std::string> const &undefmacros =
  889. vm["undefine"].as<vector<std::string> >();
  890. vector<std::string>::const_iterator end = undefmacros.end();
  891. for (vector<std::string>::const_iterator cit = undefmacros.begin();
  892. cit != end; ++cit)
  893. {
  894. ctx.remove_macro_definition(*cit, true);
  895. }
  896. }
  897. #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS == 0
  898. // suppress expansion of specified macros
  899. if (vm.count("noexpand")) {
  900. vector<std::string> const &noexpandmacros =
  901. vm["noexpand"].as<vector<std::string> >();
  902. vector<std::string>::const_iterator end = noexpandmacros.end();
  903. for (vector<std::string>::const_iterator cit = noexpandmacros.begin();
  904. cit != end; ++cit)
  905. {
  906. ctx.get_hooks().add_noexpandmacro(*cit);
  907. }
  908. }
  909. #endif
  910. // maximal include nesting depth
  911. if (vm.count("nesting")) {
  912. int max_depth = vm["nesting"].as<int>();
  913. if (max_depth < 1 || max_depth > 100000) {
  914. cerr << "wave: bogus maximal include nesting depth: "
  915. << max_depth << endl;
  916. return -1;
  917. }
  918. ctx.set_max_include_nesting_depth(max_depth);
  919. }
  920. // open the output file
  921. if (vm.count("output")) {
  922. // try to open the file, where to put the preprocessed output
  923. fs::path out_file (boost::wave::util::create_path(
  924. vm["output"].as<std::string>()));
  925. if (out_file == "-") {
  926. allow_output = false; // inhibit output initially
  927. default_outfile = "-";
  928. }
  929. else {
  930. out_file = boost::wave::util::complete_path(out_file);
  931. boost::wave::util::create_directories(
  932. boost::wave::util::branch_path(out_file));
  933. output.open(out_file.string().c_str());
  934. if (!output.is_open()) {
  935. cerr << "wave: could not open output file: "
  936. << out_file.string() << endl;
  937. return -1;
  938. }
  939. if (!license.empty())
  940. output << license;
  941. default_outfile = out_file.string();
  942. }
  943. }
  944. else if (!input_is_stdin && vm.count("autooutput")) {
  945. // generate output in the file <input_base_name>.i
  946. fs::path out_file (boost::wave::util::create_path(file_name));
  947. std::string basename (boost::wave::util::leaf(out_file));
  948. std::string::size_type pos = basename.find_last_of(".");
  949. if (std::string::npos != pos)
  950. basename = basename.substr(0, pos);
  951. out_file = boost::wave::util::branch_path(out_file) / (basename + ".i");
  952. boost::wave::util::create_directories(
  953. boost::wave::util::branch_path(out_file));
  954. output.open(out_file.string().c_str());
  955. if (!output.is_open()) {
  956. cerr << "wave: could not open output file: "
  957. << out_file.string() << endl;
  958. return -1;
  959. }
  960. if (!license.empty())
  961. output << license;
  962. default_outfile = out_file.string();
  963. }
  964. // we assume the session to be interactive if input is stdin and output is
  965. // stdout and the output is not inhibited
  966. bool is_interactive = input_is_stdin && !output.is_open() && allow_output;
  967. if (is_interactive) {
  968. // if interactive we don't warn for missing endif's etc.
  969. ctx.set_language(
  970. boost::wave::enable_single_line(ctx.get_language()), false);
  971. }
  972. // analyze the input file
  973. context_type::iterator_type first = ctx.begin();
  974. context_type::iterator_type last = ctx.end();
  975. // preprocess the required include files
  976. if (vm.count("forceinclude")) {
  977. // add the filenames to force as include files in _reverse_ order
  978. // the second parameter 'is_last' of the force_include function should
  979. // be set to true for the last (first given) file.
  980. std::vector<std::string> const &force =
  981. vm["forceinclude"].as<std::vector<std::string> >();
  982. std::vector<std::string>::const_reverse_iterator rend = force.rend();
  983. for (std::vector<std::string>::const_reverse_iterator cit = force.rbegin();
  984. cit != rend; /**/)
  985. {
  986. std::string filename(*cit);
  987. first.force_include(filename.c_str(), ++cit == rend);
  988. }
  989. }
  990. elapsed_time.set_print_time(!input_is_stdin && vm.count("timer") > 0);
  991. if (is_interactive) {
  992. print_interactive_version(); // print welcome message
  993. load_state(vm, ctx); // load the internal tables from disc
  994. }
  995. else if (vm.count("state")) {
  996. // the option "state" is usable in interactive mode only
  997. cerr << "wave: ignoring the command line option 'state', "
  998. << "use it in interactive mode only." << endl;
  999. }
  1000. // >>>>>>>>>>>>> The actual preprocessing happens here. <<<<<<<<<<<<<<<<<<<
  1001. // loop over the input lines if reading from stdin, otherwise this loop
  1002. // will be executed once
  1003. do {
  1004. // loop over all generated tokens outputting the generated text
  1005. bool finished = false;
  1006. if (input_is_stdin) {
  1007. if (is_interactive)
  1008. cout << ">>> "; // prompt if is interactive
  1009. // read next line and continue
  1010. instring.clear();
  1011. if (!read_a_line(instream, instring))
  1012. break; // end of input reached
  1013. first = ctx.begin(instring.begin(), instring.end());
  1014. }
  1015. bool need_to_advanve = false;
  1016. do {
  1017. try {
  1018. if (need_to_advanve) {
  1019. ++first;
  1020. need_to_advanve = false;
  1021. }
  1022. while (first != last) {
  1023. // store the last known good token position
  1024. current_position = (*first).get_position();
  1025. // print out the current token value
  1026. if (allow_output) {
  1027. if (!output.good()) {
  1028. cerr << "wave: problem writing to the current "
  1029. << "output file" << endl;
  1030. cerr << report_iostate_error(output.rdstate());
  1031. break;
  1032. }
  1033. if (output.is_open())
  1034. output << (*first).get_value();
  1035. else
  1036. cout << (*first).get_value();
  1037. }
  1038. // advance to the next token
  1039. ++first;
  1040. }
  1041. finished = true;
  1042. }
  1043. catch (boost::wave::cpp_exception const &e) {
  1044. // some preprocessing error
  1045. if (is_interactive || boost::wave::is_recoverable(e)) {
  1046. error_count += report_error_message(ctx, e,
  1047. treat_warnings_as_error);
  1048. need_to_advanve = true; // advance to the next token
  1049. }
  1050. else {
  1051. throw; // re-throw for non-recoverable errors
  1052. }
  1053. }
  1054. catch (boost::wave::cpplexer::lexing_exception const &e) {
  1055. // some preprocessing error
  1056. if (is_interactive ||
  1057. boost::wave::cpplexer::is_recoverable(e))
  1058. {
  1059. error_count +=
  1060. report_error_message(e, treat_warnings_as_error);
  1061. need_to_advanve = true; // advance to the next token
  1062. }
  1063. else {
  1064. throw; // re-throw for non-recoverable errors
  1065. }
  1066. }
  1067. } while (!finished);
  1068. } while (input_is_stdin);
  1069. if (is_interactive)
  1070. save_state(vm, ctx); // write the internal tables to disc
  1071. // list all defined macros at the end of the preprocessing
  1072. if (vm.count("macronames")) {
  1073. if (!list_macro_names(ctx, vm["macronames"].as<std::string>()))
  1074. return -1;
  1075. }
  1076. if (vm.count("macrocounts")) {
  1077. if (!list_macro_counts(ctx, vm["macrocounts"].as<std::string>()))
  1078. return -1;
  1079. }
  1080. }
  1081. catch (boost::wave::cpp_exception const &e) {
  1082. // some preprocessing error
  1083. report_error_message(e, treat_warnings_as_error);
  1084. return 1;
  1085. }
  1086. catch (boost::wave::cpplexer::lexing_exception const &e) {
  1087. // some lexing error
  1088. report_error_message(e, treat_warnings_as_error);
  1089. return 2;
  1090. }
  1091. catch (std::exception const &e) {
  1092. // use last recognized token to retrieve the error position
  1093. cerr
  1094. << current_position << ": "
  1095. << "exception caught: " << e.what()
  1096. << endl;
  1097. return 3;
  1098. }
  1099. catch (...) {
  1100. // use last recognized token to retrieve the error position
  1101. cerr
  1102. << current_position << ": "
  1103. << "unexpected exception caught." << endl;
  1104. return 4;
  1105. }
  1106. return -error_count; // returns the number of errors as a negative integer
  1107. }
  1108. ///////////////////////////////////////////////////////////////////////////////
  1109. // main entry point
  1110. int
  1111. main (int argc, char *argv[])
  1112. {
  1113. const std::string accepted_w_args[] = {"error"};
  1114. // test Wave compilation configuration
  1115. if (!BOOST_WAVE_TEST_CONFIGURATION()) {
  1116. cout << "wave: warning: the library this application was linked against was compiled "
  1117. << endl
  1118. << " using a different configuration (see wave_config.hpp)."
  1119. << endl;
  1120. }
  1121. // analyze the command line options and arguments
  1122. try {
  1123. // declare the options allowed on the command line only
  1124. po::options_description desc_cmdline ("Options allowed on the command line only");
  1125. desc_cmdline.add_options()
  1126. ("help,h", "print out program usage (this message)")
  1127. ("version,v", "print the version number")
  1128. ("copyright", "print out the copyright statement")
  1129. ("config-file", po::value<vector<std::string> >()->composing(),
  1130. "specify a config file (alternatively: @filepath)")
  1131. ;
  1132. const std::string w_arg_desc = "Warning settings. Currently supported: -W" +
  1133. boost::algorithm::join(accepted_w_args, ", -W");
  1134. // declare the options allowed on command line and in config files
  1135. po::options_description desc_generic ("Options allowed additionally in a config file");
  1136. desc_generic.add_options()
  1137. ("output,o", po::value<std::string>(),
  1138. "specify a file [arg] to use for output instead of stdout or "
  1139. "disable output [-]")
  1140. ("autooutput,E",
  1141. "output goes into a file named <input_basename>.i")
  1142. ("license", po::value<std::string>(),
  1143. "prepend the content of the specified file to each created file")
  1144. ("include,I", po::value<cmd_line_utils::include_paths>()->composing(),
  1145. "specify an additional include directory")
  1146. ("sysinclude,S", po::value<vector<std::string> >()->composing(),
  1147. "specify an additional system include directory")
  1148. ("forceinclude,F", po::value<std::vector<std::string> >()->composing(),
  1149. "force inclusion of the given file")
  1150. ("define,D", po::value<std::vector<std::string> >()->composing(),
  1151. "specify a macro to define (as macro[=[value]])")
  1152. ("predefine,P", po::value<std::vector<std::string> >()->composing(),
  1153. "specify a macro to predefine (as macro[=[value]])")
  1154. ("undefine,U", po::value<std::vector<std::string> >()->composing(),
  1155. "specify a macro to undefine")
  1156. #if BOOST_WAVE_USE_DEPRECIATED_PREPROCESSING_HOOKS == 0
  1157. ("noexpand,N", po::value<std::vector<std::string> >()->composing(),
  1158. "specify a macro name, which should not be expanded")
  1159. #endif
  1160. ("nesting,n", po::value<int>(),
  1161. "specify a new maximal include nesting depth")
  1162. ("warning,W", po::value<std::vector<std::string> >()->composing(),
  1163. w_arg_desc.c_str())
  1164. ;
  1165. po::options_description desc_ext ("Extended options (allowed everywhere)");
  1166. desc_ext.add_options()
  1167. ("traceto,t", po::value<std::string>(),
  1168. "output macro expansion tracing information to a file [arg] "
  1169. "or to stderr [-]")
  1170. ("timer", "output overall elapsed computing time to stderr")
  1171. ("long_long", "enable long long support in C++ mode")
  1172. #if BOOST_WAVE_SUPPORT_VARIADICS_PLACEMARKERS != 0
  1173. ("variadics", "enable certain C99 extensions in C++ mode")
  1174. ("c99", "enable C99 mode (implies --variadics)")
  1175. #endif
  1176. #if BOOST_WAVE_SUPPORT_CPP0X != 0
  1177. ("c++11", "enable C++11 mode (implies --variadics and --long_long)")
  1178. #endif
  1179. ("listincludes,l", po::value<std::string>(),
  1180. "list names of included files to a file [arg] or to stdout [-]")
  1181. ("macronames,m", po::value<std::string>(),
  1182. "list all defined macros to a file [arg] or to stdout [-]")
  1183. ("macrocounts,c", po::value<std::string>(),
  1184. "list macro invocation counts to a file [arg] or to stdout [-]")
  1185. ("preserve,p", po::value<int>()->default_value(0),
  1186. "preserve whitespace\n"
  1187. "0: no whitespace is preserved (default),\n"
  1188. "1: begin of line whitespace is preserved,\n"
  1189. "2: comments and begin of line whitespace is preserved,\n"
  1190. "3: all whitespace is preserved")
  1191. ("line,L", po::value<int>()->default_value(1),
  1192. "control the generation of #line directives\n"
  1193. "0: no #line directives are generated,\n"
  1194. "1: #line directives will be emitted (default),\n"
  1195. "2: #line directives will be emitted using relative\n"
  1196. " filenames")
  1197. ("disambiguate", po::value<int>()->default_value(1),
  1198. "control whitespace insertion to disambiguate\n"
  1199. "consecutive tokens\n"
  1200. "0: no additional whitespace is generated,\n"
  1201. "1: whitespace is used to disambiguate output (default)")
  1202. ("extended,x", "enable the #pragma wave system() directive")
  1203. #if BOOST_WAVE_SUPPORT_PRAGMA_ONCE != 0
  1204. ("noguard,G", "disable include guard detection")
  1205. ("listguards,g", po::value<std::string>(),
  1206. "list names of files flagged as 'include once' to a file [arg] "
  1207. "or to stdout [-]")
  1208. #endif
  1209. #if BOOST_WAVE_SERIALIZATION != 0
  1210. ("state,s", po::value<std::string>(),
  1211. "load and save state information from/to the given file [arg] "
  1212. "or 'wave.state' [-] (interactive mode only)")
  1213. #endif
  1214. ;
  1215. // combine the options for the different usage schemes
  1216. po::options_description desc_overall_cmdline;
  1217. po::options_description desc_overall_cfgfile;
  1218. desc_overall_cmdline.add(desc_cmdline).add(desc_generic).add(desc_ext);
  1219. desc_overall_cfgfile.add(desc_generic).add(desc_ext);
  1220. // parse command line and store results
  1221. using namespace boost::program_options::command_line_style;
  1222. po::parsed_options opts(po::parse_command_line(argc, argv,
  1223. desc_overall_cmdline, unix_style, cmd_line_utils::at_option_parser));
  1224. po::variables_map vm;
  1225. po::store(opts, vm);
  1226. po::notify(vm);
  1227. // // Try to find a wave.cfg in the same directory as the executable was
  1228. // // started from. If this exists, treat it as a wave config file
  1229. // fs::path filename(argv[0]);
  1230. //
  1231. // filename = filename.branch_path() / "wave.cfg";
  1232. // cmd_line_utils::read_config_file_options(filename.string(),
  1233. // desc_overall_cfgfile, vm, true);
  1234. // extract the arguments from the parsed command line
  1235. vector<po::option> arguments;
  1236. std::remove_copy_if(opts.options.begin(), opts.options.end(),
  1237. back_inserter(arguments), cmd_line_utils::is_argument());
  1238. // try to find a config file somewhere up the filesystem hierarchy
  1239. // starting with the input file path. This allows to use a general wave.cfg
  1240. // file for all files in a certain project.
  1241. if (arguments.size() > 0 && arguments[0].value[0] != "-") {
  1242. // construct full path of input file
  1243. fs::path input_dir (boost::wave::util::complete_path(
  1244. boost::wave::util::create_path(arguments[0].value[0])));
  1245. // chop of file name
  1246. input_dir = boost::wave::util::branch_path(
  1247. boost::wave::util::normalize(input_dir));
  1248. // walk up the hierarchy, trying to find a file wave.cfg
  1249. while (!input_dir.empty()) {
  1250. fs::path filename = input_dir / "wave.cfg";
  1251. if (cmd_line_utils::read_config_file_options(filename.string(),
  1252. desc_overall_cfgfile, vm, true))
  1253. {
  1254. break; // break on the first cfg file found
  1255. }
  1256. input_dir = boost::wave::util::branch_path(input_dir);
  1257. }
  1258. }
  1259. // if there is specified at least one config file, parse it and add the
  1260. // options to the main variables_map
  1261. if (vm.count("config-file")) {
  1262. vector<std::string> const &cfg_files =
  1263. vm["config-file"].as<vector<std::string> >();
  1264. vector<std::string>::const_iterator end = cfg_files.end();
  1265. for (vector<std::string>::const_iterator cit = cfg_files.begin();
  1266. cit != end; ++cit)
  1267. {
  1268. // parse a single config file and store the results
  1269. cmd_line_utils::read_config_file_options(*cit,
  1270. desc_overall_cfgfile, vm);
  1271. }
  1272. }
  1273. // validate warning settings
  1274. if (vm.count("warning"))
  1275. {
  1276. BOOST_FOREACH(const std::string& arg,
  1277. vm["warning"].as<std::vector<std::string> >())
  1278. {
  1279. if (boost::range::find(accepted_w_args, arg) ==
  1280. boost::end(accepted_w_args))
  1281. {
  1282. cerr << "wave: Invalid warning setting: " << arg << endl;
  1283. return -1;
  1284. }
  1285. }
  1286. }
  1287. // ... act as required
  1288. if (vm.count("help")) {
  1289. po::options_description desc_help (
  1290. "Usage: wave [options] [@config-file(s)] [file]");
  1291. desc_help.add(desc_cmdline).add(desc_generic).add(desc_ext);
  1292. cout << desc_help << endl;
  1293. return 1;
  1294. }
  1295. if (vm.count("version")) {
  1296. cout << get_version() << endl;
  1297. return 0;
  1298. }
  1299. if (vm.count("copyright")) {
  1300. return print_copyright();
  1301. }
  1302. // if there is no input file given, then take input from stdin
  1303. if (0 == arguments.size() || 0 == arguments[0].value.size() ||
  1304. arguments[0].value[0] == "-")
  1305. {
  1306. // preprocess the given input from stdin
  1307. return do_actual_work("<stdin>", std::cin, vm, true);
  1308. }
  1309. else {
  1310. if (arguments.size() > 1) {
  1311. // this driver understands to parse one input file only
  1312. cerr << "wave: more than one input file specified, "
  1313. << "ignoring all but the first!" << endl;
  1314. }
  1315. std::string file_name(arguments[0].value[0]);
  1316. ifstream instream(file_name.c_str());
  1317. // preprocess the given input file
  1318. if (!instream.is_open()) {
  1319. cerr << "wave: could not open input file: " << file_name << endl;
  1320. return -1;
  1321. }
  1322. return do_actual_work(file_name, instream, vm, false);
  1323. }
  1324. }
  1325. catch (std::exception const &e) {
  1326. cout << "wave: exception caught: " << e.what() << endl;
  1327. return 6;
  1328. }
  1329. catch (...) {
  1330. cerr << "wave: unexpected exception caught." << endl;
  1331. return 7;
  1332. }
  1333. }