diff --git a/.gitignore b/.gitignore index 53b50d7..228f52b 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ temp *.d tester roflcat +build diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..5f94163 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,24 @@ +include(CMakeDependentOption) +cmake_minimum_required(VERSION 3.1) +project(roflcat) + +#c++17 without compiler extensions +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +find_package(Curses REQUIRED) +find_library(TINFO_LIBRARY tinfo) +if(NOT TINFO_LIBRARY) + set(TINFO_LIBRARY "") +endif() +set(INCLUDE_PATH ${CMAKE_SOURCE_DIR}/include) + +add_executable (roflcat src/roflcat.cpp src/cmd.cpp) +target_include_directories(roflcat PUBLIC ${INCLUDE_PATH}) +target_include_directories(roflcat PUBLIC ${CURSES_INCLUDE_DIRS} ${TINFO_INCLUDE_DIRS}) +target_link_libraries(roflcat PRIVATE ${CURSES_LIBRARIES} ${TINFO_LIBRARY}) +install(TARGETS roflcat RUNTIME DESTINATION bin) + +#uninstall target +add_custom_target(uninstall cat install_manifest.txt | xargs rm) diff --git a/include/basic_color_printer.tpp b/include/basic_color_printer.tpp index 4b521c0..55ed45b 100644 --- a/include/basic_color_printer.tpp +++ b/include/basic_color_printer.tpp @@ -31,12 +31,16 @@ template constexpr basic_color_printer::basic_color_printer(const cmd_args& args)noexcept: - color_printer_base>(args), + color_printer_base>(args, args.invert ? L"\033[38;5;0m\033[48;5;%sm" : L"\033[38;5;%sm"), m_randomness(rand()%color_lookup_len){} template basic_color_printer& basic_color_printer::_print(const wchar_t s)noexcept{ if(s == L'\n'){ inc_line(); + if(this->m_invert) + this->reset(); + putwchar(L'\n'); + return *this; }else{ int width = wcwidth(s); if(width > 0) @@ -49,7 +53,7 @@ basic_color_printer& basic_color_printer::_print(const wchar_t s)noexcept{ new_index += color_lookup_len; if(new_index != m_index){ m_index = new_index; - wprintf(L"\033[38;5;%sm", color_lookup_table[m_index]); + wprintf(this->m_color_str, color_lookup_table[m_index]); } putwchar(s); return *this; diff --git a/include/cmd.hpp b/include/cmd.hpp index cae872f..556fd64 100644 --- a/include/cmd.hpp +++ b/include/cmd.hpp @@ -45,11 +45,12 @@ struct cmd_args{ std::vector filenames; //lolcat options + long seed = 0; float freq = 0.2f; float spread = 0.3f; - long seed = 0; unsigned truecol:1; unsigned color:2; + unsigned invert:1; //GNU cat options unsigned number:2; diff --git a/include/color_printer_base.hpp b/include/color_printer_base.hpp index 7eb3d7e..ffdbfd2 100644 --- a/include/color_printer_base.hpp +++ b/include/color_printer_base.hpp @@ -27,12 +27,15 @@ template class color_printer_base : public printer_base { protected: + const wchar_t* const m_color_str; const float m_freq; const float m_spread; + const bool m_invert; protected: - constexpr color_printer_base(const cmd_args& args)noexcept: + constexpr color_printer_base(const cmd_args& args, const wchar_t* col_str)noexcept: printer_base(args.tabs ? SHOW_TABS_STRING : L" ", args), - m_freq(args.freq), m_spread(m_freq < 0 ? -args.spread : args.spread){} + m_color_str(col_str), + m_freq(args.freq), m_spread(m_freq < 0 ? -args.spread : args.spread), m_invert(args.invert){} Derived& _reset(void){ wprintf(L"\033[0m"); return static_cast(*this); diff --git a/include/color_printer_true.hpp b/include/color_printer_true.hpp index 9776f89..202bf1c 100644 --- a/include/color_printer_true.hpp +++ b/include/color_printer_true.hpp @@ -49,7 +49,7 @@ private: color curr = color::red; - constexpr color_state(void)noexcept{ + color_state(void)noexcept{ switch(rand()%3){ case 0: r = color_max_amount; @@ -95,8 +95,8 @@ private: } }m_line_color = {}, m_color = m_line_color; public: - constexpr color_printer_true(const cmd_args& args)noexcept: - color_printer_base(args){} + color_printer_true(const cmd_args& args)noexcept: + color_printer_base(args, args.invert ? L"\033[38;5;0m\033[48;2;%s;%s;%sm" : L"\033[38;2;%s;%s;%sm"){} protected: color_printer_true& _print(const wchar_t s)noexcept{ @@ -104,6 +104,10 @@ protected: if(s == L'\n'){ inc_line(); updated = true; + if(m_invert) + reset(); + putwchar(L'\n'); + return *this; }else{ int width = wcwidth(s); if(width > 0) @@ -112,10 +116,13 @@ protected: updated = inc_color(1); } if(updated) - wprintf(L"\033[38;2;%s;%s;%sm", lookup_table[m_color.r], lookup_table[m_color.g], lookup_table[m_color.b]); + wprintf(m_color_str, lookup_table[m_color.r], lookup_table[m_color.g], lookup_table[m_color.b]); putwchar(s); return *this; } + color_printer_true& _reset(void){ + return color_printer_base::_reset(); + } constexpr void inc_line(void){ int amount = m_spread*(float{color_max_amount}/4); _do_inc_color(amount, m_line_color); diff --git a/include/printer_base.hpp b/include/printer_base.hpp index 9bab6fa..19f30bc 100644 --- a/include/printer_base.hpp +++ b/include/printer_base.hpp @@ -71,11 +71,11 @@ protected: constexpr printer_base(const wchar_t* tabstr, const cmd_args& args)noexcept; ~printer_base(void)noexcept = default; public: - constexpr Derived& print(wchar_t s)noexcept(noexcept(std::declval()._print(s))); - constexpr Derived& print(const wchar_t* s)noexcept(noexcept(std::declval>().print(std::declval()))); - constexpr Derived& print(char s); - constexpr Derived& print(const char* s); - constexpr Derived& reset(void); + Derived& print(wchar_t s)noexcept(noexcept(std::declval()._print(s))); + Derived& print(const wchar_t* s)noexcept(noexcept(std::declval>().print(std::declval()))); + Derived& print(char s); + Derived& print(const char* s); + Derived& reset(void); }; #endif diff --git a/include/printer_base.tpp b/include/printer_base.tpp index d59698e..9a9a02b 100644 --- a/include/printer_base.tpp +++ b/include/printer_base.tpp @@ -39,7 +39,7 @@ constexpr printer_base::printer_base(const wchar_t* tabstr, const cmd_a m_tab_size(wcslen(tabstr)){} template -constexpr auto printer_base::print(wchar_t s)noexcept(noexcept(std::declval()._print(s))) -> Derived&{ +auto printer_base::print(wchar_t s)noexcept(noexcept(std::declval()._print(s))) -> Derived&{ Derived& dv = static_cast(*this); //suppress repeated blank lines if(m_squeeze_blank){ @@ -88,27 +88,27 @@ constexpr auto printer_base::print(wchar_t s)noexcept(noexcept(std::dec } template -constexpr auto printer_base::print(const wchar_t* s)noexcept(noexcept(std::declval>().print(std::declval()))) -> Derived&{ +auto printer_base::print(const wchar_t* s)noexcept(noexcept(std::declval>().print(std::declval()))) -> Derived&{ for(;*s != 0;++s){ print(*s); } return static_cast(*this); } template -constexpr auto printer_base::print(char s) -> Derived&{ +auto printer_base::print(char s) -> Derived&{ wchar_t tmp; mbstowcs(&tmp, &s, 1); return print(tmp); } template -constexpr auto printer_base::print(const char* s) -> Derived&{ +auto printer_base::print(const char* s) -> Derived&{ for(;*s != 0;++s){ print(*s); } return static_cast(*this); } template -constexpr auto printer_base::reset(void) -> Derived&{ +auto printer_base::reset(void) -> Derived&{ if constexpr(HAS_FUNC(_reset)::value){ return static_cast(*this)._reset(); }else{ diff --git a/makefile b/makefile deleted file mode 100644 index 6032124..0000000 --- a/makefile +++ /dev/null @@ -1,86 +0,0 @@ -#This program is free software: you can redistribute it and/or modify -#it under the terms of the GNU General Public License as published by -#the Free Software Foundation, either version 3 of the License, or -#(at your option) any later version. - -#This program is distributed in the hope that it will be useful, -#but WITHOUT ANY WARRANTY; without even the implied warranty of -#MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -#GNU General Public License for more details. - -#You should have received a copy of the GNU General Public License -#along with this program. If not, see . - -#Copyright 2018 rexy712 - - -SOURCE_DIRS:=src -OBJDIR:=obj -DEPDIR:=$(OBJDIR)/dep -INCLUDE_DIRS:=include -EXT:=cpp -MAIN_EXECUTABLE:=tester - -CXX:=g++ -CXXFLAGS:=-g -std=c++17 -Wall -pedantic -Wextra -fno-exceptions -fno-rtti -all: CXXFLAGS+=-O0 -release: CXXFLAGS+=-O2 -LDFLAGS= -LDLIBS:=-lncurses -STRIP:=strip - -memchk:LDFLAGS+=-fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls -memchk:CXXFLAGS+=-O0 -fsanitize=address -fno-omit-frame-pointer -fno-optimize-sibling-calls - -ifeq ($(OS),Windows_NT) - mkdir=mkdir $(subst /,\,$(1)) > NUL 2>&1 - rm=del /F $(1) > NUL 2>&1 - rmdir=rd /s /q $(1) > NUL 2>&1 - move=move /y $(subst /,\,$(1)) $(subst /,\,$(2)) > NUL 2>&1 - MAIN_EXECUTABLE:=$(MAIN_EXECUTABLE).exe - LDLIBS:=-lglfw3 -lSOIL -lgl3w -lm -lopengl32 -lglu32 -lgdi32 -lkernel32 -else - mkdir=mkdir -p $(1) - rm=rm -f $(1) - rmdir=rm -rf $(1) - move=mv $(1) $(2) -endif - -INTERNAL_CXXFLAGS=-c $(foreach dir,$(INCLUDE_DIRS),-I"$(dir)") -MMD -MP -MF"$(DEPDIR)/$(notdir $(patsubst %.o,%.d,$@))" -SOURCES:=$(foreach source,$(SOURCE_DIRS),$(foreach ext,$(EXT),$(wildcard $(source)/*.$(ext)))) -OBJECTS:=$(addprefix $(OBJDIR)/,$(subst \,.,$(subst /,.,$(addsuffix .o,$(SOURCES))))) - -all: $(MAIN_EXECUTABLE) -memchk: $(MAIN_EXECUTABLE) - -$(MAIN_EXECUTABLE): $(OBJECTS) - $(CXX) $(LDFLAGS) $^ -o "$(basename $@)" $(LDLIBS) - -.PHONY: release -release: $(OBJECTS) - $(CXX) $(LDFLAGS) $^ -o "$(basename $(MAIN_EXECUTABLE))" $(LDLIBS) - $(STRIP) --strip-all "$(MAIN_EXECUTABLE)" - -define GENERATE_OBJECTS - -$$(OBJDIR)/$(subst \,.,$(subst /,.,$(1))).%.o: $(1)/% - $$(CXX) $$(CXXFLAGS) $$(INTERNAL_CXXFLAGS) "$$<" -o "$$@" - -endef - -$(foreach dir,$(SOURCE_DIRS),$(eval $(call GENERATE_OBJECTS,$(dir)))) -$(OBJECTS): | $(OBJDIR) $(DEPDIR) - -$(OBJDIR): - $(call mkdir,"$@") -$(DEPDIR): - $(call mkdir,"$@") - -.PHONY: clean -clean: - $(call rmdir,"$(DEPDIR)") - $(call rmdir,"$(OBJDIR)") - $(call rm,"$(MAIN_EXECUTABLE)") - --include $(wildcard $(DEPDIR)/*.d) - diff --git a/src/cmd.cpp b/src/cmd.cpp index 679b7d7..f1d17fc 100644 --- a/src/cmd.cpp +++ b/src/cmd.cpp @@ -82,6 +82,7 @@ static constexpr const char FREQ_LONG_OPTION[] = "freq" REQ_FLOAT_AR static constexpr const char TRUECOLOR_LONG_OPTION[] = "truecolor"; static constexpr const char FORCE_COLOR_LONG_OPTION[] = "force"; static constexpr const char DISABLE_COLOR_LONG_OPTION[] = "no-color"; +static constexpr const char INVERT_LONG_OPTION[] = "invert"; static constexpr const char IGNORE_ANIMATE_LONG_OPTION[] = "animate"; static constexpr const char IGNORE_DURATION_LONG_OPTION[] = "duration" REQ_INTEGER_ARG; @@ -96,6 +97,7 @@ static constexpr const char SHOW_ENDS_SHORT_OPTION[] = "E"; static constexpr const char FORCE_COLOR_SHORT_OPTION[] = "f"; static constexpr const char FREQ_SHORT_OPTION[] = "F"; static constexpr const char USAGE_SHORT_OPTION[] = "h"; +static constexpr const char INVERT_SHORT_OPTION[] = "i"; static constexpr const char NUMBER_LINES_SHORT_OPTION[] = "n"; static constexpr const char DISABLE_COLOR_SHORT_OPTION[] = "N"; static constexpr const char SPREAD_SHORT_OPTION[] = "p"; @@ -135,6 +137,7 @@ static constexpr const char TRUECOLOR_DESC[] = "24-bit (truecolor) static constexpr const char FORCE_COLOR_DESC[] = "Force color even when stdout is not a tty"; static constexpr const char DISABLE_COLOR_DESC_BASE[] = "Suppress color even when stdout is a tty, overrides -"; static constexpr const char* DISABLE_COLOR_DESC = concat_many_strs::str; +static constexpr const char INVERT_DESC[] = "Change background color instead of foreground"; static constexpr const char* IGNORE_ANIMATE_DESC = IGNORED_DESC; static constexpr const char* IGNORE_DURATION_DESC = IGNORED_DESC; @@ -198,7 +201,7 @@ static constexpr size_t strlen_pre_eq(const char* str){ #define CHECK_VALID_SHORT_ARG(opt, arg, type) \ { \ - if(next_arg == (argc-1) || !is_##type(arg)){ \ + if(next_arg == argc || !is_##type(arg)){ \ fwprintf(stderr, L"'-%s' requires an argument of type " #type "\n", opt); \ ret.error = 1; \ break; \ @@ -223,6 +226,8 @@ cmd_args process_cmd_args(int argc, char** argv){ } if(!strcmp(argv[i], "--")){ escaped = true; + }else if(!strcmp(argv[i], "-")){ + ret.filenames.push_back(argv[i]); }else if(IS_SHORT_OPTION(argv[i])){ size_t arg_len = strlen(argv[i]); int next_arg = i+1; @@ -274,6 +279,9 @@ cmd_args process_cmd_args(int argc, char** argv){ if(ret.color == COLOR_DEFAULT) ret.color = COLOR_FORCE; break; + case SHORT_OPT(INVERT): + ret.invert = 1; + break; case SHORT_OPT(SEED): CHECK_VALID_SHORT_INT_ARG(SEED, argv[next_arg]); ret.seed = atol(argv[next_arg]); @@ -329,6 +337,8 @@ cmd_args process_cmd_args(int argc, char** argv){ }else if(CHECK_LONG_OPTION(FORCE_COLOR, arg)){ if(ret.color == COLOR_DEFAULT) ret.color = COLOR_FORCE; + }else if(CHECK_LONG_OPTION(INVERT, arg)){ + ret.invert = 1; }else if(CHECK_LONG_OPTION_WITH_ARG(SEED, arg)){ constexpr size_t offset = strlen_pre_eq(SEED_LONG_OPTION); CHECK_VALID_LONG_INT_ARG(SEED, offset, arg); @@ -381,6 +391,7 @@ const cmd_options cmd_arguments_list[] = { OPTION(IGNORE_ANIMATE), OPTION(IGNORE_DURATION), OPTION(IGNORE_SPEED), + OPTION(INVERT), {nullptr,0,nullptr}, OPTION(USAGE), OPTION(VERSION) diff --git a/src/roflcat.cpp b/src/roflcat.cpp index eef15ec..cd1e9c2 100644 --- a/src/roflcat.cpp +++ b/src/roflcat.cpp @@ -34,7 +34,7 @@ #include //std::chrono::* #include //srand -constexpr const char* version_string = "roflcat version 0.1a"; +constexpr const char version_string[] = "roflcat version 1.0"; static constexpr size_t constexpr_strlen(const char* str){ size_t i = 0; @@ -126,6 +126,7 @@ int print_files(cmd_args& args){ if(in == L'\n') //Only reset on newline to save print overhead p.reset(); } + clearerr(stdin); }else{ //everything besides stdin FILE* fp = fopen(args.filenames[i], "r"); if(!fp){