http://www.boost.org/LICENSE_1_0.txt)
=============================================================================*/
#include "files.hpp"
-#include <boost/filesystem/fstream.hpp>
-#include <boost/unordered_map.hpp>
-#include <boost/range/algorithm/upper_bound.hpp>
-#include <boost/range/algorithm/transform.hpp>
-#include <boost/foreach.hpp>
#include <fstream>
#include <iterator>
#include <vector>
+#include <boost/filesystem/fstream.hpp>
+#include <boost/foreach.hpp>
+#include <boost/range/algorithm/transform.hpp>
+#include <boost/range/algorithm/upper_bound.hpp>
+#include <boost/unordered_map.hpp>
namespace quickbook
{
// probably broken.
template <typename InputIterator, typename OutputIterator>
- bool check_bom(InputIterator& begin, InputIterator end,
- OutputIterator out, char const* chars, int length)
+ bool check_bom(
+ InputIterator& begin,
+ InputIterator end,
+ OutputIterator out,
+ char const* chars,
+ int length)
{
char const* ptr = chars;
- while(begin != end && *begin == *ptr) {
+ while (begin != end && *begin == *ptr) {
++begin;
++ptr;
--length;
- if(length == 0) return true;
+ if (length == 0) return true;
}
// Failed to match, so write the skipped characters to storage:
- while(chars != ptr) *out++ = *chars++;
+ while (chars != ptr)
+ *out++ = *chars++;
return false;
}
template <typename InputIterator, typename OutputIterator>
- std::string read_bom(InputIterator& begin, InputIterator end,
- OutputIterator out)
+ std::string read_bom(
+ InputIterator& begin, InputIterator end, OutputIterator out)
{
- if(begin == end) return "";
+ if (begin == end) return "";
- const char* utf8 = "\xef\xbb\xbf" ;
+ const char* utf8 = "\xef\xbb\xbf";
const char* utf32be = "\0\0\xfe\xff";
const char* utf32le = "\xff\xfe\0\0";
unsigned char c = *begin;
- switch(c)
- {
+ switch (c) {
case 0xEF: { // UTF-8
return check_bom(begin, end, out, utf8, 3) ? "UTF-8" : "";
}
case 0xFF: // UTF-16/UTF-32 little endian
- return !check_bom(begin, end, out, utf32le, 2) ? "" :
- check_bom(begin, end, out, utf32le + 2, 2) ? "UTF-32" : "UTF-16";
+ return !check_bom(begin, end, out, utf32le, 2)
+ ? ""
+ : check_bom(begin, end, out, utf32le + 2, 2) ? "UTF-32"
+ : "UTF-16";
case 0: // UTF-32 big endian
return check_bom(begin, end, out, utf32be, 4) ? "UTF-32" : "";
case 0xFE: // UTF-16 big endian
// newlines.
template <typename InputIterator, typename OutputIterator>
- void normalize(InputIterator begin, InputIterator end,
- OutputIterator out)
+ void normalize(InputIterator begin, InputIterator end, OutputIterator out)
{
std::string encoding = read_bom(begin, end, out);
- if(encoding != "UTF-8" && encoding != "")
- throw load_error(encoding +
- " is not supported. Please use UTF-8.");
+ if (encoding != "UTF-8" && encoding != "")
+ throw load_error(encoding + " is not supported. Please use UTF-8.");
- while(begin != end) {
- if(*begin == '\r') {
+ while (begin != end) {
+ if (*begin == '\r') {
*out++ = '\n';
++begin;
- if(begin != end && *begin == '\n') ++begin;
+ if (begin != end && *begin == '\n') ++begin;
}
else {
*out++ = *begin++;
file_ptr load(fs::path const& filename, unsigned qbk_version)
{
- boost::unordered_map<fs::path, file_ptr>::iterator pos
- = files.find(filename);
+ boost::unordered_map<fs::path, file_ptr>::iterator pos =
+ files.find(filename);
- if (pos == files.end())
- {
+ if (pos == files.end()) {
fs::ifstream in(filename, std::ios_base::in);
- if (!in)
- throw load_error("Could not open input file.");
+ if (!in) throw load_error("Could not open input file.");
// Turn off white space skipping on the stream
in.unsetf(std::ios::skipws);
std::string source;
normalize(
- std::istream_iterator<char>(in),
- std::istream_iterator<char>(),
+ std::istream_iterator<char>(in), std::istream_iterator<char>(),
std::back_inserter(source));
- if (in.bad())
- throw load_error("Error reading input file.");
+ if (in.bad()) throw load_error("Error reading input file.");
bool inserted;
}
file_position relative_position(
- string_iterator begin,
- string_iterator iterator)
+ string_iterator begin, string_iterator iterator)
{
file_position pos;
string_iterator line_begin = begin;
- while (begin != iterator)
- {
- if (*begin == '\r')
- {
+ while (begin != iterator) {
+ if (*begin == '\r') {
++begin;
++pos.line;
line_begin = begin;
}
- else if (*begin == '\n')
- {
+ else if (*begin == '\n') {
++begin;
++pos.line;
line_begin = begin;
if (begin == iterator) break;
- if (*begin == '\r')
- {
+ if (*begin == '\r') {
++begin;
line_begin = begin;
}
}
- else
- {
+ else {
++begin;
}
}
struct mapped_file_section
{
- enum section_types {
+ enum section_types
+ {
normal,
empty,
indented
};
-
+
std::string::size_type original_pos;
std::string::size_type our_pos;
section_types section_type;
explicit mapped_file_section(
- std::string::size_type original_pos_,
- std::string::size_type our_pos_,
- section_types section_type_ = normal) :
- original_pos(original_pos_), our_pos(our_pos_),
- section_type(section_type_) {}
+ std::string::size_type original_pos_,
+ std::string::size_type our_pos_,
+ section_types section_type_ = normal)
+ : original_pos(original_pos_)
+ , our_pos(our_pos_)
+ , section_type(section_type_)
+ {
+ }
};
struct mapped_section_original_cmp
{
- bool operator()(mapped_file_section const& x,
- mapped_file_section const& y)
+ bool operator()(
+ mapped_file_section const& x, mapped_file_section const& y)
{
return x.original_pos < y.original_pos;
}
- bool operator()(mapped_file_section const& x,
- std::string::size_type const& y)
+ bool operator()(
+ mapped_file_section const& x, std::string::size_type const& y)
{
return x.original_pos < y;
}
- bool operator()(std::string::size_type const& x,
- mapped_file_section const& y)
+ bool operator()(
+ std::string::size_type const& x, mapped_file_section const& y)
{
return x < y.original_pos;
}
struct mapped_section_pos_cmp
{
- bool operator()(mapped_file_section const& x,
- mapped_file_section const& y)
+ bool operator()(
+ mapped_file_section const& x, mapped_file_section const& y)
{
return x.our_pos < y.our_pos;
}
- bool operator()(mapped_file_section const& x,
- std::string::size_type const& y)
+ bool operator()(
+ mapped_file_section const& x, std::string::size_type const& y)
{
return x.our_pos < y;
}
- bool operator()(std::string::size_type const& x,
- mapped_file_section const& y)
+ bool operator()(
+ std::string::size_type const& x, mapped_file_section const& y)
{
return x < y.our_pos;
}
};
-
+
struct mapped_file : file
{
- explicit mapped_file(file_ptr original_) :
- file(*original_, std::string()),
- original(original_), mapped_sections()
- {}
+ explicit mapped_file(file_ptr original_)
+ : file(*original_, std::string())
+ , original(original_)
+ , mapped_sections()
+ {
+ }
file_ptr original;
std::vector<mapped_file_section> mapped_sections;
-
- void add_empty_mapped_file_section(string_iterator pos) {
+
+ void add_empty_mapped_file_section(string_iterator pos)
+ {
std::string::size_type original_pos =
pos - original->source().begin();
-
+
if (mapped_sections.empty() ||
- mapped_sections.back().section_type !=
- mapped_file_section::empty ||
- mapped_sections.back().original_pos != original_pos)
- {
+ mapped_sections.back().section_type !=
+ mapped_file_section::empty ||
+ mapped_sections.back().original_pos != original_pos) {
mapped_sections.push_back(mapped_file_section(
- original_pos, source().size(),
- mapped_file_section::empty));
+ original_pos, source().size(), mapped_file_section::empty));
}
}
- void add_mapped_file_section(string_iterator pos) {
+ void add_mapped_file_section(string_iterator pos)
+ {
mapped_sections.push_back(mapped_file_section(
pos - original->source().begin(), source().size()));
}
std::string::size_type pos) const
{
switch (section->section_type) {
- case mapped_file_section::normal:
- return pos - section->our_pos + section->original_pos;
-
- case mapped_file_section::empty:
- return section->original_pos;
-
- case mapped_file_section::indented: {
- // Will contain the start of the current line.
- quickbook::string_view::size_type our_line = section->our_pos;
-
- // Will contain the number of lines in the block before
- // the current line.
- unsigned newline_count = 0;
-
- for(quickbook::string_view::size_type i = section->our_pos;
- i != pos; ++i)
- {
- if (source()[i] == '\n') {
- our_line = i + 1;
- ++newline_count;
- }
- }
+ case mapped_file_section::normal:
+ return pos - section->our_pos + section->original_pos;
- // The start of the line in the original source.
- quickbook::string_view::size_type original_line =
- section->original_pos;
-
- while(newline_count > 0) {
- if (original->source()[original_line] == '\n')
- --newline_count;
- ++original_line;
- }
+ case mapped_file_section::empty:
+ return section->original_pos;
- // The start of line content (i.e. after indentation).
- our_line = skip_indentation(source(), our_line);
+ case mapped_file_section::indented: {
+ // Will contain the start of the current line.
+ quickbook::string_view::size_type our_line = section->our_pos;
- // The position is in the middle of indentation, so
- // just return the start of the whitespace, which should
- // be good enough.
- if (our_line > pos) return original_line;
+ // Will contain the number of lines in the block before
+ // the current line.
+ unsigned newline_count = 0;
- original_line =
- skip_indentation(original->source(), original_line);
+ for (quickbook::string_view::size_type i = section->our_pos;
+ i != pos; ++i) {
+ if (source()[i] == '\n') {
+ our_line = i + 1;
+ ++newline_count;
+ }
+ }
- // Confirm that we are actually in the same position.
- assert(original->source()[original_line] ==
- source()[our_line]);
+ // The start of the line in the original source.
+ quickbook::string_view::size_type original_line =
+ section->original_pos;
- // Calculate the position
- return original_line + (pos - our_line);
+ while (newline_count > 0) {
+ if (original->source()[original_line] == '\n')
+ --newline_count;
+ ++original_line;
}
- default:
- assert(false);
- return section->original_pos;
+
+ // The start of line content (i.e. after indentation).
+ our_line = skip_indentation(source(), our_line);
+
+ // The position is in the middle of indentation, so
+ // just return the start of the whitespace, which should
+ // be good enough.
+ if (our_line > pos) return original_line;
+
+ original_line =
+ skip_indentation(original->source(), original_line);
+
+ // Confirm that we are actually in the same position.
+ assert(original->source()[original_line] == source()[our_line]);
+
+ // Calculate the position
+ return original_line + (pos - our_line);
+ }
+ default:
+ assert(false);
+ return section->original_pos;
}
}
-
+
std::vector<mapped_file_section>::const_iterator find_section(
string_iterator pos) const
{
std::vector<mapped_file_section>::const_iterator section =
- boost::upper_bound(mapped_sections,
+ boost::upper_bound(
+ mapped_sections,
std::string::size_type(pos - source().begin()),
mapped_section_pos_cmp());
assert(section != mapped_sections.begin());
virtual file_position position_of(string_iterator) const;
- private:
-
+ private:
static std::string::size_type skip_indentation(
- quickbook::string_view src, std::string::size_type i)
+ quickbook::string_view src, std::string::size_type i)
{
- while (i != src.size() && (src[i] == ' ' || src[i] == '\t')) ++i;
+ while (i != src.size() && (src[i] == ' ' || src[i] == '\t'))
+ ++i;
return i;
}
-
};
- namespace {
+ namespace
+ {
std::list<mapped_file> mapped_files;
}
{
mapped_file_builder_data() { reset(); }
void reset() { new_file.reset(); }
-
+
boost::intrusive_ptr<mapped_file> new_file;
};
return r;
}
- void mapped_file_builder::clear()
- {
- data->reset();
- }
-
+ void mapped_file_builder::clear() { data->reset(); }
+
bool mapped_file_builder::empty() const
{
return data->new_file->source().empty();
{
return data->new_file->source().size();
}
-
+
void mapped_file_builder::add_at_pos(quickbook::string_view x, iterator pos)
{
data->new_file->add_empty_mapped_file_section(pos);
add(x, 0, x.data->new_file->source_.size());
}
- void mapped_file_builder::add(mapped_file_builder const& x,
- pos_type begin, pos_type end)
+ void mapped_file_builder::add(
+ mapped_file_builder const& x, pos_type begin, pos_type end)
{
assert(data->new_file->original == x.data->new_file->original);
assert(begin <= x.data->new_file->source_.size());
assert(end <= x.data->new_file->source_.size());
- if (begin != end)
- {
+ if (begin != end) {
std::vector<mapped_file_section>::const_iterator i =
x.data->new_file->find_section(
x.data->new_file->source().begin() + begin);
-
+
std::string::size_type size = data->new_file->source_.size();
-
+
data->new_file->mapped_sections.push_back(mapped_file_section(
- x.data->new_file->to_original_pos(i, begin),
- size, i->section_type));
-
+ x.data->new_file->to_original_pos(i, begin), size,
+ i->section_type));
+
for (++i; i != x.data->new_file->mapped_sections.end() &&
- i->our_pos < end; ++i)
- {
+ i->our_pos < end;
+ ++i) {
data->new_file->mapped_sections.push_back(mapped_file_section(
i->original_pos, i->our_pos - begin + size,
i->section_type));
}
-
+
data->new_file->source_.append(
x.data->new_file->source_.begin() + begin,
- x.data->new_file->source_.begin() + end);
+ x.data->new_file->source_.begin() + end);
}
}
- quickbook::string_view::size_type indentation_count(quickbook::string_view x)
+ quickbook::string_view::size_type indentation_count(
+ quickbook::string_view x)
{
unsigned count = 0;
- for(string_iterator begin = x.begin(), end = x.end();
- begin != end; ++begin)
- {
- switch(*begin)
- {
+ for (string_iterator begin = x.begin(), end = x.end(); begin != end;
+ ++begin) {
+ switch (*begin) {
case ' ':
++count;
break;
std::string const program(x.begin(), x.end());
// Erase leading blank lines and newlines:
- std::string::size_type text_start = program.find_first_not_of(" \t\r\n");
+ std::string::size_type text_start =
+ program.find_first_not_of(" \t\r\n");
if (text_start == std::string::npos) return;
text_start = program.find_last_of("\r\n", text_start);
assert(text_start < program.size());
// Get the first line indentation
- std::string::size_type indent = program.find_first_not_of(" \t", text_start) - text_start;
+ std::string::size_type indent =
+ program.find_first_not_of(" \t", text_start) - text_start;
quickbook::string_view::size_type full_indent = indentation_count(
quickbook::string_view(&program[text_start], indent));
// Calculate the minimum indent from the rest of the lines
// Detecting a mix of spaces and tabs.
- while (std::string::npos != (pos = program.find_first_of("\r\n", pos)))
- {
+ while (std::string::npos !=
+ (pos = program.find_first_of("\r\n", pos))) {
pos = program.find_first_not_of("\r\n", pos);
if (std::string::npos == pos) break;
char ch = program[n];
if (ch == '\r' || ch == '\n') continue; // ignore empty lines
- indent = (std::min)(indent, n-pos);
- full_indent = (std::min)(full_indent, indentation_count(
- quickbook::string_view(&program[pos], n-pos)));
+ indent = (std::min)(indent, n - pos);
+ full_indent = (std::min)(
+ full_indent, indentation_count(quickbook::string_view(
+ &program[pos], n - pos)));
}
// Detect if indentation is mixed.
quickbook::string_view first_indent(&program[text_start], indent);
pos = text_start;
- while (std::string::npos != (pos = program.find_first_of("\r\n", pos)))
- {
+ while (std::string::npos !=
+ (pos = program.find_first_of("\r\n", pos))) {
pos = program.find_first_not_of("\r\n", pos);
if (std::string::npos == pos) break;
std::string::size_type n = program.find_first_not_of(" \t", pos);
- if (n == std::string::npos || n-pos < indent) continue;
+ if (n == std::string::npos || n - pos < indent) continue;
if (quickbook::string_view(&program[pos], indent) != first_indent) {
mixed_indentation = true;
pos = text_start;
do {
- if (std::string::npos == (pos = program.find_first_not_of("\r\n", pos)))
+ if (std::string::npos ==
+ (pos = program.find_first_not_of("\r\n", pos)))
break;
- unindented_program.append(program.begin() + copy_start, program.begin() + pos);
+ unindented_program.append(
+ program.begin() + copy_start, program.begin() + pos);
copy_start = pos;
// Find the end of the indentation.
std::string::size_type next = program.find_first_not_of(" \t", pos);
if (next == std::string::npos) next = program.size();
- if (mixed_indentation)
- {
- string_view::size_type length = indentation_count(quickbook::string_view(
- &program[pos], next - pos));
+ if (mixed_indentation) {
+ string_view::size_type length = indentation_count(
+ quickbook::string_view(&program[pos], next - pos));
if (length > full_indent) {
std::string new_indentation(length - full_indent, ' ');
copy_start = next;
}
- else
- {
+ else {
copy_start = (std::min)(pos + indent, next);
}
pos = next;
} while (std::string::npos !=
- (pos = program.find_first_of("\r\n", pos)));
+ (pos = program.find_first_of("\r\n", pos)));
unindented_program.append(program.begin() + copy_start, program.end());
file_position mapped_file::position_of(string_iterator pos) const
{
- return original->position_of(original->source().begin() +
+ return original->position_of(
+ original->source().begin() +
to_original_pos(find_section(pos), pos - source().begin()));
}
}