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