in thrift/compiler/parse/parsing_driver.cc [288:428]
t_doc parsing_driver::clean_up_doctext(std::string docstring) {
// Convert to C++ string, and remove Windows's carriage returns.
docstring.erase(
remove(docstring.begin(), docstring.end(), '\r'), docstring.end());
// Separate into lines.
std::vector<std::string> lines;
std::string::size_type pos = std::string::npos;
std::string::size_type last;
while (true) {
last = (pos == std::string::npos) ? 0 : pos + 1;
pos = docstring.find('\n', last);
if (pos == std::string::npos) {
// First bit of cleaning. If the last line is only whitespace, drop it.
std::string::size_type nonwhite =
docstring.find_first_not_of(" \t", last);
if (nonwhite != std::string::npos) {
lines.push_back(docstring.substr(last));
}
break;
}
lines.push_back(docstring.substr(last, pos - last));
}
// A very profound docstring.
if (lines.empty()) {
return boost::none;
}
// Clear leading whitespace from the first line.
pos = lines.front().find_first_not_of(" \t");
lines.front().erase(0, pos);
// If every nonblank line after the first has the same number of spaces/tabs,
// then a comment prefix, remove them.
enum Prefix {
None = 0,
Star = 1, // length of '*'
Slashes = 3, // length of '///'
InlineSlash = 4, // length of '///<'
};
Prefix found_prefix = None;
std::string::size_type prefix_len = 0;
std::vector<std::string>::iterator l_iter;
// Start searching for prefixes from second line, since lexer already removed
// initial prefix/suffix.
for (l_iter = lines.begin() + 1; l_iter != lines.end(); ++l_iter) {
if (l_iter->empty()) {
continue;
}
pos = l_iter->find_first_not_of(" \t");
if (found_prefix == None) {
if (pos != std::string::npos) {
if (l_iter->at(pos) == '*') {
found_prefix = Star;
prefix_len = pos;
} else if (l_iter->compare(pos, 4, "///<") == 0) {
found_prefix = InlineSlash;
prefix_len = pos;
} else if (l_iter->compare(pos, 3, "///") == 0) {
found_prefix = Slashes;
prefix_len = pos;
} else {
found_prefix = None;
break;
}
} else {
// Whitespace-only line. Truncate it.
l_iter->clear();
}
} else if (
l_iter->size() > pos && pos == prefix_len &&
((found_prefix == Star && l_iter->at(pos) == '*') ||
(found_prefix == InlineSlash &&
l_iter->compare(pos, 4, "///<") == 0) ||
(found_prefix == Slashes && l_iter->compare(pos, 3, "///") == 0))) {
// Business as usual
} else if (pos == std::string::npos) {
// Whitespace-only line. Let's truncate it for them.
l_iter->clear();
} else {
// The pattern has been broken.
found_prefix = None;
break;
}
}
// If our prefix survived, delete it from every line.
if (found_prefix != None) {
// Get the prefix too.
prefix_len += found_prefix;
for (l_iter = lines.begin() + 1; l_iter != lines.end(); ++l_iter) {
l_iter->erase(0, prefix_len);
}
}
// Now delete the minimum amount of leading whitespace from each line.
prefix_len = std::string::npos;
for (l_iter = lines.begin() + 1; l_iter != lines.end(); ++l_iter) {
if (l_iter->empty()) {
continue;
}
pos = l_iter->find_first_not_of(" \t");
if (pos != std::string::npos &&
(prefix_len == std::string::npos || pos < prefix_len)) {
prefix_len = pos;
}
}
// If our whitespace prefix survived, delete it from every line.
if (prefix_len != std::string::npos) {
for (l_iter = lines.begin() + 1; l_iter != lines.end(); ++l_iter) {
l_iter->erase(0, prefix_len);
}
}
// Remove trailing whitespace from every line.
for (l_iter = lines.begin(); l_iter != lines.end(); ++l_iter) {
pos = l_iter->find_last_not_of(" \t");
if (pos != std::string::npos && pos != l_iter->length() - 1) {
l_iter->erase(pos + 1);
}
}
// If the first line is empty, remove it.
// Don't do this earlier because a lot of steps skip the first line.
if (lines.front().empty()) {
lines.erase(lines.begin());
}
// Now rejoin the lines and copy them back into doctext.
docstring.clear();
for (l_iter = lines.begin(); l_iter != lines.end(); ++l_iter) {
docstring += *l_iter;
docstring += '\n';
}
return docstring;
}