1 /*=============================================================================
2 Copyright (c) 2002 2004 2006 Joel de Guzman
3 Copyright (c) 2004 Eric Niebler
4 http://spirit.sourceforge.net/
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"
13 #include "actions.hpp"
14 #include "post_process.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>
39 #if (defined(BOOST_MSVC) && (BOOST_MSVC <= 1310))
40 #pragma warning(disable:4355)
43 #define QUICKBOOK_VERSION "Quickbook Version 1.6.2"
47 namespace cl
= boost::spirit::classic
;
48 namespace fs
= boost::filesystem
;
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
;
58 static void set_macros(quickbook::state
& state
)
60 for(std::vector
<std::string
>::const_iterator
61 it
= preset_defines
.begin(),
62 end
= preset_defines
.end();
65 boost::string_ref
val(*it
);
66 parse_iterator
first(val
.begin());
67 parse_iterator
last(val
.end());
69 cl::parse_info
<parse_iterator
> info
=
70 cl::parse(first
, last
, state
.grammar().command_line_macro
);
74 << "Error parsing command line definition: '"
83 ///////////////////////////////////////////////////////////////////////////
87 ///////////////////////////////////////////////////////////////////////////
88 void parse_file(quickbook::state
& state
, value include_doc_id
, bool nested_file
)
90 parse_iterator
first(state
.current_file
->source().begin());
91 parse_iterator
last(state
.current_file
->source().end());
93 cl::parse_info
<parse_iterator
> info
= cl::parse(first
, last
, state
.grammar().doc_info
);
96 if (!state
.error_count
)
98 parse_iterator pos
= info
.stop
;
99 std::string doc_type
= pre(state
, pos
, include_doc_id
, nested_file
);
101 info
= cl::parse(info
.hit
? info
.stop
: first
, last
, state
.grammar().block_start
);
103 post(state
, doc_type
);
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";
115 struct parse_document_options
117 parse_document_options() :
121 deps_out_flags(quickbook::dependency_tracker::default_
)
128 quickbook::dependency_tracker::flags deps_out_flags
;
129 fs::path locations_out
;
130 fs::path xinclude_base
;
135 fs::path
const& filein_
136 , fs::path
const& fileout_
137 , parse_document_options
const& options_
)
139 string_stream buffer
;
140 document_state output
;
145 quickbook::state
state(filein_
, options_
.xinclude_base
, buffer
, output
);
148 if (state
.error_count
== 0) {
149 state
.dependencies
.add_dependency(filein_
);
150 state
.current_file
= load(filein_
); // Throws load_error
154 if(state
.error_count
) {
156 << "Error count: " << state
.error_count
<< ".\n";
160 result
= state
.error_count
? 1 : 0;
162 if (!options_
.deps_out
.empty())
164 state
.dependencies
.write_dependencies(options_
.deps_out
,
165 options_
.deps_out_flags
);
168 if (!options_
.locations_out
.empty())
170 fs::ofstream
out(options_
.locations_out
);
171 state
.dependencies
.write_dependencies(options_
.locations_out
,
172 dependency_tracker::checked
);
175 catch (load_error
& e
) {
176 detail::outerr(filein_
) << e
.what() << std::endl
;
179 catch (std::runtime_error
& e
) {
180 detail::outerr() << e
.what() << std::endl
;
184 if (!fileout_
.empty() && result
== 0)
186 std::string stage2
= output
.replace_placeholders(buffer
.str());
188 fs::ofstream
fileout(fileout_
);
190 if (fileout
.fail()) {
191 ::quickbook::detail::outerr()
192 << "Error opening output file "
199 if (options_
.pretty_print
)
203 fileout
<< post_process(stage2
, options_
.indent
,
206 catch (quickbook::post_process_failure
&)
209 ::quickbook::detail::outerr()
210 << "Post Processing Failed."
221 if (fileout
.fail()) {
222 ::quickbook::detail::outerr()
223 << "Error writing to output file "
235 ///////////////////////////////////////////////////////////////////////////
239 ///////////////////////////////////////////////////////////////////////////
241 main(int argc
, char* argv
[])
245 namespace fs
= boost::filesystem
;
246 namespace po
= boost::program_options
;
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
;
257 using quickbook::detail::command_line_string
;
259 // First thing, the filesystem should record the current working directory.
260 fs::initial_path
<fs::path
>();
262 // Various initialisation methods
263 quickbook::detail::initialise_output();
264 quickbook::detail::initialise_markups();
266 // Declare the program options
268 options_description
desc("Allowed options");
269 options_description
hidden("Hidden options");
270 options_description
all("All options");
272 #if QUICKBOOK_WIDE_PATHS
273 #define PO_VALUE po::wvalue
275 #define PO_VALUE po::value
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")
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 "
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 '-' "
309 "This is deprecated, use 'output-deps-format=checked' to "
310 "write the deps file in this format.")
313 all
.add(desc
).add(hidden
);
315 positional_options_description p
;
316 p
.add("input-file", -1);
318 // Read option from the command line
322 #if QUICKBOOK_WIDE_PATHS
323 quickbook::ignore_variable(&argc
);
324 quickbook::ignore_variable(&argv
);
327 LPWSTR
* wide_argv
= CommandLineToArgvW(GetCommandLineW(), &wide_argc
);
330 quickbook::detail::outerr() << "Error getting argument values." << std::endl
;
335 wcommand_line_parser(wide_argc
, wide_argv
)
340 LocalFree(wide_argv
);
342 store(command_line_parser(argc
, argv
)
350 // Process the command line options
352 quickbook::parse_document_options parse_document_options
;
353 bool expect_errors
= vm
.count("expect-errors");
356 if (vm
.count("help"))
358 std::ostringstream description_text
;
359 description_text
<< desc
;
361 quickbook::detail::out() << description_text
.str() << "\n";
366 if (vm
.count("version"))
368 std::string boost_version
= BOOST_LIB_VERSION
;
369 boost::replace(boost_version
, '_', '.');
371 quickbook::detail::out()
380 quickbook::detail::set_ms_errors(vm
.count("ms-errors"));
382 if (vm
.count("no-pretty-print"))
383 parse_document_options
.pretty_print
= false;
385 quickbook::self_linked_headers
= !vm
.count("no-self-link-headers");
387 if (vm
.count("indent"))
388 parse_document_options
.indent
= vm
["indent"].as
<int>();
390 if (vm
.count("linewidth"))
391 parse_document_options
.linewidth
= vm
["linewidth"].as
<int>();
393 if (vm
.count("debug"))
396 timeinfo
.tm_year
= 2000 - 1900;
397 timeinfo
.tm_mon
= 12 - 1;
398 timeinfo
.tm_mday
= 20;
399 timeinfo
.tm_hour
= 12;
402 timeinfo
.tm_isdst
= -1;
404 quickbook::current_time
= &timeinfo
;
405 quickbook::current_gm_time
= &timeinfo
;
406 quickbook::debug_mode
= true;
410 time_t t
= std::time(0);
411 static tm lt
= *localtime(&t
);
412 static tm gmt
= *gmtime(&t
);
413 quickbook::current_time
= <
;
414 quickbook::current_gm_time
= &gmt
;
415 quickbook::debug_mode
= false;
418 quickbook::include_path
.clear();
419 if (vm
.count("include-path"))
422 vm
["include-path"].as
<std::vector
<command_line_string
> >(),
423 std::back_inserter(quickbook::include_path
),
424 quickbook::detail::command_line_to_path
);
427 quickbook::preset_defines
.clear();
428 if (vm
.count("define"))
431 vm
["define"].as
<std::vector
<command_line_string
> >(),
432 std::back_inserter(quickbook::preset_defines
),
433 quickbook::detail::command_line_to_utf8
);
436 if (vm
.count("input-file"))
438 fs::path filein
= quickbook::detail::command_line_to_path(
439 vm
["input-file"].as
<command_line_string
>());
442 bool default_output
= true;
444 if (vm
.count("output-deps"))
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;
452 if (vm
.count("output-deps-format"))
454 std::string format_flags
=
455 quickbook::detail::command_line_to_utf8(
456 vm
["output-deps-format"].as
<command_line_string
>());
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
);
465 BOOST_FOREACH(std::string
const& flag
, flag_names
) {
466 if (flag
== "checked") {
467 flags
|= quickbook::dependency_tracker::checked
;
469 else if (flag
== "escaped") {
470 flags
|= quickbook::dependency_tracker::escaped
;
472 else if (!flag
.empty()) {
473 quickbook::detail::outerr()
474 << "Unknown dependency format flag: "
482 parse_document_options
.deps_out_flags
=
483 quickbook::dependency_tracker::flags(flags
);
486 if (vm
.count("output-checked-locations"))
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;
494 if (vm
.count("output-file"))
496 fileout
= quickbook::detail::command_line_to_path(
497 vm
["output-file"].as
<command_line_string
>());
499 else if (default_output
)
502 fileout
.replace_extension(".xml");
505 if (vm
.count("xinclude-base"))
507 parse_document_options
.xinclude_base
=
508 quickbook::detail::command_line_to_path(
509 vm
["xinclude-base"].as
<command_line_string
>());
513 parse_document_options
.xinclude_base
= fileout
.parent_path();
514 if (parse_document_options
.xinclude_base
.empty())
515 parse_document_options
.xinclude_base
= ".";
518 if (!fs::is_directory(parse_document_options
.xinclude_base
))
520 quickbook::detail::outerr()
521 << (vm
.count("xinclude-base") ?
522 "xinclude-base is not a directory" :
523 "parent directory not found for output file");
527 if (vm
.count("image-location"))
529 quickbook::image_location
= quickbook::detail::command_line_to_path(
530 vm
["image-location"].as
<command_line_string
>());
534 quickbook::image_location
= filein
.parent_path() / "html";
537 if (!fileout
.empty()) {
538 quickbook::detail::out() << "Generating Output File: "
544 error_count
+= quickbook::parse_document(
545 filein
, fileout
, parse_document_options
);
549 if (!error_count
) quickbook::detail::outerr() << "No errors detected for --expect-errors." << std::endl
;
559 std::ostringstream description_text
;
560 description_text
<< desc
;
562 quickbook::detail::outerr() << "No filename given\n\n"
563 << description_text
.str() << std::endl
;
568 catch(std::exception
& e
)
570 quickbook::detail::outerr() << e
.what() << "\n";
576 quickbook::detail::outerr() << "Exception of unknown type caught\n";