diff --git a/nazuna/.gitignore b/nazuna/.gitignore new file mode 100644 index 0000000..1fb75c7 --- /dev/null +++ b/nazuna/.gitignore @@ -0,0 +1,8 @@ +*.o +*.swp +.DS_Store + +## Output +bin/ +build/ +*.xcodeproj diff --git a/nazuna/Makefile b/nazuna/Makefile new file mode 100644 index 0000000..cf85085 --- /dev/null +++ b/nazuna/Makefile @@ -0,0 +1,17 @@ +NORI = ../nori/bin/nori +PRODUCTNAME = nazuna +HEADERS = ../somera/*.h +SOURCES = ../somera/*.cpp main.cpp + +xcode: + $(NORI) \ + -generator=xcode \ + -o $(PRODUCTNAME) \ + -std=c++14 \ + -stdlib=libc++ \ + -I.. \ + $(HEADERS) \ + $(SOURCES) + @xcodebuild -project $(PRODUCTNAME).xcodeproj -configuration Release + @mkdir -p bin + @cp build/Release/$(PRODUCTNAME) bin/$(PRODUCTNAME) diff --git a/nazuna/README.md b/nazuna/README.md new file mode 100644 index 0000000..a5f1fa6 --- /dev/null +++ b/nazuna/README.md @@ -0,0 +1,24 @@ +# nazuna + +A simple C/C++ refactoring tool. + +It is distributed under the [MIT License](https://opensource.org/licenses/MIT). + +## Features + +* Add new line to end of file. +* Replace tabs with white spaces +* Remove trailing spaces, tabs and extra newlines + +## Build and run + +```sh +# Setup build tool +make -C ../nori bootstrap + +# Build +make xcode + +# Run +./bin/nazuna -help +``` diff --git a/nazuna/main.cpp b/nazuna/main.cpp new file mode 100644 index 0000000..1db93a3 --- /dev/null +++ b/nazuna/main.cpp @@ -0,0 +1,100 @@ +// Copyright (c) 2015 mogemimi. Distributed under the MIT license. + +#include "somera/CommandLineParser.h" +#include "somera/FileSystem.h" +#include "somera/Optional.h" +#include "somera/StringHelper.h" +#include +#include + +using somera::CommandLineParser; +using somera::Optional; +using somera::NullOpt; +namespace StringHelper = somera::StringHelper; + +namespace { + +void setupCommandLineParser(CommandLineParser & parser) +{ + using somera::CommandLineArgumentType::Flag; + using somera::CommandLineArgumentType::JoinedOrSeparate; + parser.setUsageText("norichan [options ...] [build file ...]"); + parser.addArgument("-h", Flag, "Display available options"); + parser.addArgument("-help", Flag, "Display available options"); +} + +std::string removeUnnecessaryWhitespace(const std::string& text) +{ + using StringHelper::trimRight; + std::string result; + for (auto & line : StringHelper::split(text, '\n')) { + result += trimRight(trimRight(line, ' '), '\t'); + result += '\n'; + } + return std::move(result); +} + +std::string replaceHardTabsWithWhiteSpaces(const std::string& text) +{ + constexpr auto spaces = " "; + return StringHelper::replace(text, "\t", spaces); +} + +std::string replaceCRLFWithLF(const std::string& text) +{ + return StringHelper::replace(text, "\r\n", "\n"); +} + +std::string trimLastLineBreaks(const std::string& text) +{ + return StringHelper::trimRight(text, '\n') + '\n'; +} + +void refactorSourceCode(const std::string& path) +{ + std::ifstream input(path); + if (!input) { + return; + } + std::istreambuf_iterator start(input); + std::istreambuf_iterator end; + std::string text(start, end); + input.close(); + + std::ofstream output(path, std::ios::out | std::ios::trunc); + if (!output) { + return; + } + text = replaceCRLFWithLF(text); + text = replaceHardTabsWithWhiteSpaces(text); + text = removeUnnecessaryWhitespace(text); + text = trimLastLineBreaks(text); + output << text; +} + +} // unnamed namespace + +int main(int argc, char *argv[]) +{ + CommandLineParser parser; + setupCommandLineParser(parser); + parser.parse(argc, argv); + + if (parser.hasParseError()) { + std::cerr << parser.getErrorMessage() << std::endl; + return 1; + } + if (parser.exists("-h") || parser.exists("-help")) { + std::cout << parser.getHelpText() << std::endl; + return 0; + } + if (parser.getPaths().empty()) { + std::cerr << "error: no input file" << std::endl; + return 1; + } + + for (auto & path : parser.getPaths()) { + refactorSourceCode(path); + } + return 0; +}