]> git.proxmox.com Git - ceph.git/blob - ceph/src/boost/tools/quickbook/src/quickbook.cpp
update sources to v12.2.3
[ceph.git] / ceph / src / boost / tools / quickbook / src / quickbook.cpp
1 /*=============================================================================
2 Copyright (c) 2002 2004 2006 Joel de Guzman
3 Copyright (c) 2004 Eric Niebler
4 http://spirit.sourceforge.net/
5
6 Use, modification and distribution is subject to the Boost Software
7 License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
8 http://www.boost.org/LICENSE_1_0.txt)
9 =============================================================================*/
10 #include "grammar.hpp"
11 #include "quickbook.hpp"
12 #include "state.hpp"
13 #include "actions.hpp"
14 #include "post_process.hpp"
15 #include "utils.hpp"
16 #include "files.hpp"
17 #include "stream.hpp"
18 #include "path.hpp"
19 #include "document_state.hpp"
20 #include <boost/program_options.hpp>
21 #include <boost/filesystem/path.hpp>
22 #include <boost/filesystem/operations.hpp>
23 #include <boost/filesystem/fstream.hpp>
24 #include <boost/range/algorithm.hpp>
25 #include <boost/ref.hpp>
26 #include <boost/version.hpp>
27 #include <boost/foreach.hpp>
28 #include <boost/algorithm/string/split.hpp>
29 #include <boost/algorithm/string/classification.hpp>
30
31 #include <stdexcept>
32 #include <vector>
33 #include <iterator>
34
35 #if defined(_WIN32)
36 #include <windows.h>
37 #include <shellapi.h>
38 #endif
39
40 #if (defined(BOOST_MSVC) && (BOOST_MSVC <= 1310))
41 #pragma warning(disable:4355)
42 #endif
43
44 #define QUICKBOOK_VERSION "Quickbook Version 1.7.0"
45
46 namespace quickbook
47 {
48 namespace cl = boost::spirit::classic;
49 namespace fs = boost::filesystem;
50
51 tm* current_time; // the current time
52 tm* current_gm_time; // the current UTC time
53 bool debug_mode; // for quickbook developers only
54 bool self_linked_headers;
55 std::vector<fs::path> include_path;
56 std::vector<std::string> preset_defines;
57 fs::path image_location;
58
59 static void set_macros(quickbook::state& state)
60 {
61 for(std::vector<std::string>::const_iterator
62 it = preset_defines.begin(),
63 end = preset_defines.end();
64 it != end; ++it)
65 {
66 quickbook::string_view val(*it);
67 parse_iterator first(val.begin());
68 parse_iterator last(val.end());
69
70 cl::parse_info<parse_iterator> info =
71 cl::parse(first, last, state.grammar().command_line_macro);
72
73 if (!info.full) {
74 detail::outerr()
75 << "Error parsing command line definition: '"
76 << *it
77 << "'"
78 << std::endl;
79 ++state.error_count;
80 }
81 }
82 }
83
84 ///////////////////////////////////////////////////////////////////////////
85 //
86 // Parse a file
87 //
88 ///////////////////////////////////////////////////////////////////////////
89 void parse_file(quickbook::state& state, value include_doc_id, bool nested_file)
90 {
91 parse_iterator first(state.current_file->source().begin());
92 parse_iterator last(state.current_file->source().end());
93
94 cl::parse_info<parse_iterator> info = cl::parse(first, last, state.grammar().doc_info);
95 assert(info.hit);
96
97 if (!state.error_count)
98 {
99 std::string doc_type = pre(state, info.stop, include_doc_id, nested_file);
100
101 info = cl::parse(info.hit ? info.stop : first, last, state.grammar().block_start);
102
103 post(state, doc_type);
104
105 if (!info.full)
106 {
107 file_position const& pos = state.current_file->position_of(info.stop.base());
108 detail::outerr(state.current_file->path, pos.line)
109 << "Syntax Error near column " << pos.column << ".\n";
110 ++state.error_count;
111 }
112 }
113 }
114
115 struct parse_document_options
116 {
117 parse_document_options() :
118 indent(-1),
119 linewidth(-1),
120 pretty_print(true),
121 strict_mode(false),
122 deps_out_flags(quickbook::dependency_tracker::default_)
123 {}
124
125 int indent;
126 int linewidth;
127 bool pretty_print;
128 bool strict_mode;
129 fs::path deps_out;
130 quickbook::dependency_tracker::flags deps_out_flags;
131 fs::path locations_out;
132 fs::path xinclude_base;
133 };
134
135 static int
136 parse_document(
137 fs::path const& filein_
138 , fs::path const& fileout_
139 , parse_document_options const& options_)
140 {
141 string_stream buffer;
142 document_state output;
143
144 int result = 0;
145
146 try {
147 quickbook::state state(filein_, options_.xinclude_base, buffer, output);
148 state.strict_mode = options_.strict_mode;
149 set_macros(state);
150
151 if (state.error_count == 0) {
152 state.dependencies.add_dependency(filein_);
153 state.current_file = load(filein_); // Throws load_error
154
155 parse_file(state);
156
157 if(state.error_count) {
158 detail::outerr()
159 << "Error count: " << state.error_count << ".\n";
160 }
161 }
162
163 result = state.error_count ? 1 : 0;
164
165 if (!options_.deps_out.empty())
166 {
167 state.dependencies.write_dependencies(options_.deps_out,
168 options_.deps_out_flags);
169 }
170
171 if (!options_.locations_out.empty())
172 {
173 fs::ofstream out(options_.locations_out);
174 state.dependencies.write_dependencies(options_.locations_out,
175 dependency_tracker::checked);
176 }
177 }
178 catch (load_error& e) {
179 detail::outerr(filein_) << e.what() << std::endl;
180 result = 1;
181 }
182 catch (std::runtime_error& e) {
183 detail::outerr() << e.what() << std::endl;
184 result = 1;
185 }
186
187 if (!fileout_.empty() && result == 0)
188 {
189 std::string stage2 = output.replace_placeholders(buffer.str());
190
191 fs::ofstream fileout(fileout_);
192
193 if (fileout.fail()) {
194 ::quickbook::detail::outerr()
195 << "Error opening output file "
196 << fileout_
197 << std::endl;
198
199 return 1;
200 }
201
202 if (options_.pretty_print)
203 {
204 try
205 {
206 fileout << post_process(stage2, options_.indent,
207 options_.linewidth);
208 }
209 catch (quickbook::post_process_failure&)
210 {
211 // fallback!
212 ::quickbook::detail::outerr()
213 << "Post Processing Failed."
214 << std::endl;
215 fileout << stage2;
216 return 1;
217 }
218 }
219 else
220 {
221 fileout << stage2;
222 }
223
224 if (fileout.fail()) {
225 ::quickbook::detail::outerr()
226 << "Error writing to output file "
227 << fileout_
228 << std::endl;
229
230 return 1;
231 }
232 }
233
234 return result;
235 }
236 }
237
238 ///////////////////////////////////////////////////////////////////////////
239 //
240 // Main program
241 //
242 ///////////////////////////////////////////////////////////////////////////
243 int
244 main(int argc, char* argv[])
245 {
246 try
247 {
248 namespace fs = boost::filesystem;
249 namespace po = boost::program_options;
250
251 using boost::program_options::options_description;
252 using boost::program_options::variables_map;
253 using boost::program_options::store;
254 using boost::program_options::parse_command_line;
255 using boost::program_options::wcommand_line_parser;
256 using boost::program_options::command_line_parser;
257 using boost::program_options::notify;
258 using boost::program_options::positional_options_description;
259
260 using namespace quickbook;
261 using quickbook::detail::command_line_string;
262
263 // First thing, the filesystem should record the current working directory.
264 fs::initial_path<fs::path>();
265
266 // Various initialisation methods
267 quickbook::detail::initialise_output();
268 quickbook::detail::initialise_markups();
269
270 // Declare the program options
271
272 options_description desc("Allowed options");
273 options_description hidden("Hidden options");
274 options_description all("All options");
275
276 #if QUICKBOOK_WIDE_PATHS
277 #define PO_VALUE po::wvalue
278 #else
279 #define PO_VALUE po::value
280 #endif
281
282 desc.add_options()
283 ("help", "produce help message")
284 ("version", "print version string")
285 ("no-pretty-print", "disable XML pretty printing")
286 ("strict", "strict mode")
287 ("no-self-linked-headers", "stop headers linking to themselves")
288 ("indent", PO_VALUE<int>(), "indent spaces")
289 ("linewidth", PO_VALUE<int>(), "line width")
290 ("input-file", PO_VALUE<command_line_string>(), "input file")
291 ("output-file", PO_VALUE<command_line_string>(), "output file")
292 ("no-output", "don't write out the result (overriden by --output-file)")
293 ("output-deps", PO_VALUE<command_line_string>(), "output dependency file")
294 ("ms-errors", "use Microsoft Visual Studio style error & warn message format")
295 ("include-path,I", PO_VALUE< std::vector<command_line_string> >(), "include path")
296 ("define,D", PO_VALUE< std::vector<command_line_string> >(), "define macro")
297 ("image-location", PO_VALUE<command_line_string>(), "image location")
298 ;
299
300 hidden.add_options()
301 ("debug", "debug mode")
302 ("expect-errors",
303 "Succeed if the input file contains a correctly handled "
304 "error, fail otherwise.")
305 ("xinclude-base", PO_VALUE<command_line_string>(),
306 "Generate xincludes as if generating for this target "
307 "directory.")
308 ("output-deps-format", PO_VALUE<command_line_string>(),
309 "Comma separated list of formatting options for output-deps, "
310 "options are: escaped, checked")
311 ("output-checked-locations", PO_VALUE<command_line_string>(),
312 "Writes a file listing all the file locations that were "
313 "checked, starting with '+' if they were found, or '-' "
314 "if they weren't.\n"
315 "This is deprecated, use 'output-deps-format=checked' to "
316 "write the deps file in this format.")
317 ;
318
319 all.add(desc).add(hidden);
320
321 positional_options_description p;
322 p.add("input-file", -1);
323
324 // Read option from the command line
325
326 variables_map vm;
327
328 #if QUICKBOOK_WIDE_PATHS
329 quickbook::ignore_variable(&argc);
330 quickbook::ignore_variable(&argv);
331
332 int wide_argc;
333 LPWSTR* wide_argv = CommandLineToArgvW(GetCommandLineW(), &wide_argc);
334 if (!wide_argv)
335 {
336 quickbook::detail::outerr() << "Error getting argument values." << std::endl;
337 return 1;
338 }
339
340 store(
341 wcommand_line_parser(wide_argc, wide_argv)
342 .options(all)
343 .positional(p)
344 .run(), vm);
345
346 LocalFree(wide_argv);
347 #else
348 store(command_line_parser(argc, argv)
349 .options(all)
350 .positional(p)
351 .run(), vm);
352 #endif
353
354 notify(vm);
355
356 // Process the command line options
357
358 parse_document_options options;
359 bool expect_errors = vm.count("expect-errors");
360 int error_count = 0;
361
362 if (vm.count("help"))
363 {
364 std::ostringstream description_text;
365 description_text << desc;
366
367 quickbook::detail::out() << description_text.str() << "\n";
368
369 return 0;
370 }
371
372 if (vm.count("version"))
373 {
374 std::string boost_version = BOOST_LIB_VERSION;
375 boost::replace(boost_version, '_', '.');
376
377 quickbook::detail::out()
378 << QUICKBOOK_VERSION
379 << " (Boost "
380 << boost_version
381 << ")"
382 << std::endl;
383 return 0;
384 }
385
386 quickbook::detail::set_ms_errors(vm.count("ms-errors"));
387
388 if (vm.count("no-pretty-print"))
389 options.pretty_print = false;
390
391 options.strict_mode = !!vm.count("strict");
392
393 quickbook::self_linked_headers = !vm.count("no-self-linked-headers");
394
395 if (vm.count("indent"))
396 options.indent = vm["indent"].as<int>();
397
398 if (vm.count("linewidth"))
399 options.linewidth = vm["linewidth"].as<int>();
400
401 if (vm.count("debug"))
402 {
403 static tm timeinfo;
404 timeinfo.tm_year = 2000 - 1900;
405 timeinfo.tm_mon = 12 - 1;
406 timeinfo.tm_mday = 20;
407 timeinfo.tm_hour = 12;
408 timeinfo.tm_min = 0;
409 timeinfo.tm_sec = 0;
410 timeinfo.tm_isdst = -1;
411 mktime(&timeinfo);
412 quickbook::current_time = &timeinfo;
413 quickbook::current_gm_time = &timeinfo;
414 quickbook::debug_mode = true;
415 }
416 else
417 {
418 time_t t = std::time(0);
419 static tm lt = *localtime(&t);
420 static tm gmt = *gmtime(&t);
421 quickbook::current_time = &lt;
422 quickbook::current_gm_time = &gmt;
423 quickbook::debug_mode = false;
424 }
425
426 quickbook::include_path.clear();
427 if (vm.count("include-path"))
428 {
429 boost::transform(
430 vm["include-path"].as<std::vector<command_line_string> >(),
431 std::back_inserter(quickbook::include_path),
432 quickbook::detail::command_line_to_path);
433 }
434
435 quickbook::preset_defines.clear();
436 if (vm.count("define"))
437 {
438 boost::transform(
439 vm["define"].as<std::vector<command_line_string> >(),
440 std::back_inserter(quickbook::preset_defines),
441 quickbook::detail::command_line_to_utf8);
442 }
443
444 if (vm.count("input-file"))
445 {
446 fs::path filein = quickbook::detail::command_line_to_path(
447 vm["input-file"].as<command_line_string>());
448 fs::path fileout;
449
450 if (!fs::exists(filein)) {
451 quickbook::detail::outerr()
452 << "file not found: "
453 << filein
454 << std::endl;
455 ++error_count;
456 }
457
458 bool default_output = true;
459
460 if (vm.count("no-output"))
461 {
462 default_output = false;
463 }
464
465 if (vm.count("output-deps"))
466 {
467 options.deps_out =
468 quickbook::detail::command_line_to_path(
469 vm["output-deps"].as<command_line_string>());
470 default_output = false;
471 }
472
473 if (vm.count("output-deps-format"))
474 {
475 std::string format_flags =
476 quickbook::detail::command_line_to_utf8(
477 vm["output-deps-format"].as<command_line_string>());
478
479 std::vector<std::string> flag_names;
480 boost::algorithm::split(flag_names, format_flags,
481 boost::algorithm::is_any_of(", "),
482 boost::algorithm::token_compress_on);
483
484 unsigned flags = 0;
485
486 BOOST_FOREACH(std::string const& flag, flag_names) {
487 if (flag == "checked") {
488 flags |= quickbook::dependency_tracker::checked;
489 }
490 else if (flag == "escaped") {
491 flags |= quickbook::dependency_tracker::escaped;
492 }
493 else if (!flag.empty()) {
494 quickbook::detail::outerr()
495 << "Unknown dependency format flag: "
496 << flag
497 <<std::endl;
498
499 ++error_count;
500 }
501 }
502
503 options.deps_out_flags =
504 quickbook::dependency_tracker::flags(flags);
505 }
506
507 if (vm.count("output-checked-locations"))
508 {
509 options.locations_out =
510 quickbook::detail::command_line_to_path(
511 vm["output-checked-locations"].as<command_line_string>());
512 default_output = false;
513 }
514
515 if (vm.count("output-file"))
516 {
517 fileout = quickbook::detail::command_line_to_path(
518 vm["output-file"].as<command_line_string>());
519
520 fs::path parent = fileout.parent_path();
521 if (!parent.empty() && !fs::is_directory(parent))
522 {
523 quickbook::detail::outerr()
524 << "parent directory not found for output file"
525 << std::endl;
526 ++error_count;
527 }
528 }
529 else if (default_output)
530 {
531 fileout = filein;
532 fileout.replace_extension(".xml");
533 }
534
535 if (vm.count("xinclude-base"))
536 {
537 options.xinclude_base =
538 quickbook::detail::command_line_to_path(
539 vm["xinclude-base"].as<command_line_string>());
540
541 // I'm not sure if this error check is necessary.
542 // There might be valid reasons to use a path that doesn't
543 // exist yet, or a path that just generates valid relative
544 // paths.
545 if (!fs::is_directory(options.xinclude_base))
546 {
547 quickbook::detail::outerr()
548 << "xinclude-base is not a directory"
549 << std::endl;
550 ++error_count;
551 }
552 }
553 else
554 {
555 options.xinclude_base = fileout.parent_path();
556 if (options.xinclude_base.empty()) {
557 options.xinclude_base = ".";
558 }
559
560 // If fileout was implicitly created from filein, then it should be in filein's directory.
561 // If fileout was explicitly specified, then it's already been checked.
562 assert(error_count || fs::is_directory(options.xinclude_base));
563 }
564
565 if (vm.count("image-location"))
566 {
567 quickbook::image_location = quickbook::detail::command_line_to_path(
568 vm["image-location"].as<command_line_string>());
569 }
570 else
571 {
572 quickbook::image_location = filein.parent_path() / "html";
573 }
574
575 if (!error_count) {
576 if (!fileout.empty()) {
577 quickbook::detail::out() << "Generating Output File: "
578 << fileout
579 << std::endl;
580 }
581
582 error_count += quickbook::parse_document(
583 filein, fileout, options);
584 }
585
586 if (expect_errors)
587 {
588 if (!error_count) quickbook::detail::outerr() << "No errors detected for --expect-errors." << std::endl;
589 return !error_count;
590 }
591 else
592 {
593 return error_count;
594 }
595 }
596 else
597 {
598 std::ostringstream description_text;
599 description_text << desc;
600
601 quickbook::detail::outerr() << "No filename given\n\n"
602 << description_text.str() << std::endl;
603 return 1;
604 }
605 }
606
607 catch(std::exception& e)
608 {
609 quickbook::detail::outerr() << e.what() << "\n";
610 return 1;
611 }
612
613 catch(...)
614 {
615 quickbook::detail::outerr() << "Exception of unknown type caught\n";
616 return 1;
617 }
618
619 return 0;
620 }