Skip to content

Instantly share code, notes, and snippets.

@N-Dekker
Created October 4, 2018 18:08
Show Gist options
  • Save N-Dekker/b3b66878f1ab242fd0dce170113f1e86 to your computer and use it in GitHub Desktop.
Save N-Dekker/b3b66878f1ab242fd0dce170113f1e86 to your computer and use it in GitHub Desktop.
Script to replace leading stars by spaces in Doxygen code blocks, for patch http://review.source.kitware.com/#/c/23782
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* Script to replace leading stars ('*') by spaces in Doxygen code blocks
* Used for patch http://review.source.kitware.com/#/c/23782/
*
* Initial version by Niels Dekker, LKEB, Leiden University Medical Center, 2018
*/
#include <cassert>
#include <cctype>
#include <deque>
#include <experimental/filesystem>
#include <fstream>
#include <iostream>
#include <cstring>
#include <string>
using namespace std::experimental::filesystem::v1;
namespace
{
using Lines = std::deque<std::string>;
auto ReadFile(const path& filePath)
{
Lines result;
std::ifstream inputFileStream{ filePath };
std::string line;
while (std::getline(inputFileStream, line))
{
result.push_back(line);
}
return result;
}
void WriteFile(const path& filePath, const Lines& lines)
{
std::ofstream outputFileStream{ filePath };
for (const auto& line : lines)
{
outputFileStream << line << '\n';
}
}
const char* GoToFirstNonSpace(const char* ptr)
{
while (*ptr == ' ')
{
++ptr;
}
return ptr;
}
template <unsigned N>
bool StringStartsWithPrefix(const char*& str, const char(&prefix)[N])
{
assert(prefix[N - 1] == '\0');
if ((std::strlen(str) + 1 >= N) && (std::memcmp(str, prefix, N - 1) == 0))
{
// Move the 'str' pointer beyond the prefix.
str += N - 1;
return true;
}
return false;
}
struct Statistics
{
unsigned numberOfModifiedLines;
};
Statistics ModifyLines(Lines& lines)
{
Statistics statistics = {};
auto className = std::string{};
auto publicLineNumber = Lines::size_type{};
auto isInsideCodeSection = false;
for (auto lineNumber = Lines::size_type{}; lineNumber < lines.size(); ++lineNumber)
{
auto& line = lines[lineNumber];
const auto numberOfChars = line.size();
if (numberOfChars > 1)
{
const char* c_str = line.c_str();
if (StringStartsWithPrefix(c_str, " *"))
{
if (isInsideCodeSection)
{
if (numberOfChars == 2)
{
line.clear();
}
else
{
line[1] = ' ';
}
++statistics.numberOfModifiedLines;
}
else
{
c_str = GoToFirstNonSpace(c_str);
if (StringStartsWithPrefix(c_str, "\\code"))
{
isInsideCodeSection = true;
}
}
}
if (isInsideCodeSection && (std::strstr(c_str, "\\endcode") != nullptr))
{
isInsideCodeSection = false;
}
}
}
return statistics;
}
auto ProcessFile(const path& filePath)
{
auto lines = ReadFile(filePath);
const auto statistics = ModifyLines(lines);
if (statistics.numberOfModifiedLines > 0)
{
WriteFile(filePath, lines);
}
return statistics;
}
void ProcessDirectory(const path& directoryPath)
{
Statistics statistics = {};
const recursive_directory_iterator end;
unsigned numberOfModifiedFiles = 0;
for (recursive_directory_iterator it{ directoryPath }; it != end; ++it)
{
const auto& path = it->path();
const auto& extension = path.extension();
if ((!extension.empty()) &&
(extension.string() == ".h") &&
is_regular_file(path))
{
const auto statisticsPerFile = ProcessFile(path);
if (statisticsPerFile.numberOfModifiedLines > 0)
{
++numberOfModifiedFiles;
statistics.numberOfModifiedLines += statisticsPerFile.numberOfModifiedLines;
std::cout << numberOfModifiedFiles << ' ' << statisticsPerFile.numberOfModifiedLines << ' ' << path << std::endl;
}
}
}
std::cout
<< "numberOfModifiedFiles:\t" << numberOfModifiedFiles
<< "\nNumberOfModifiedLines:\t" << statistics.numberOfModifiedLines
<< std::endl;
}
}
int main(int argc, char** argv)
{
if (argc != 2)
{
std::cout <<
"Please specify the source directory path as command-line argument."
"\nNote: This program will modify the source files in-place!!!"
<< std::endl;
}
else
{
if (argv == nullptr)
{
return EXIT_FAILURE;
}
const char* const arg = argv[1];
if (arg == nullptr)
{
return EXIT_FAILURE;
}
ProcessDirectory(arg);
}
std::cout << "Press anything to continue" << std::endl;
std::cin.get();
return EXIT_SUCCESS;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment