Compare commits
21 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
03d2f386e1 | ||
|
|
9e1e01bb62 | ||
|
|
911375627f | ||
|
|
3928766c6b | ||
|
|
ee4c9a6ea1 | ||
|
|
ca79f26d4e | ||
|
|
e3586a9e93 | ||
|
|
72891834c2 | ||
|
|
c0abcee00b | ||
|
|
49a1f0456f | ||
|
|
2a733a0224 | ||
|
|
75aa0c2475 | ||
|
|
cb55e21846 | ||
|
|
e5cb265456 | ||
|
|
f757f23d11 | ||
|
|
c9f39be9d8 | ||
|
|
ad93eab52c | ||
|
|
0b3e857722 | ||
|
|
82da8580c5 | ||
|
|
ae77265efc | ||
|
|
df44c75bdb |
@@ -1,6 +1,7 @@
|
||||
include(CMakeDependentOption)
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
project(roflcat)
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
include(CMakeDependentOption)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
#c++17 without compiler extensions
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
|
||||
29
README.md
29
README.md
@@ -1,31 +1,42 @@
|
||||
# README
|
||||
|
||||
## About
|
||||
roflcat is a C++ rewrite of [lolcat][1] which runs much faster and supports all the options of GNU cat. I am not going to support the animation options of lolcat (--animate, --duration, --speed) because there is no real purpose to them.
|
||||
roflcat is a C++ rewrite of [lolcat][1] which runs much faster and supports all the options of GNU cat. I am not going to support the animation options of lolcat (--animate, --duration, --speed) because there is no real purpose to them.
|
||||
Currently I can only confirm it runs on a linux system and I have no desire to expand to supporting anything else at this time.
|
||||
|
||||
To keep compatability with both GNU cat and lolcat, I wanted all command line options from both to either be implemented or ignored. However there are a few conflicts between the two, namely -s -t and -v. For these I will be implementing the GNU cat functionality.
|
||||
|
||||
Current version is 0.1a as of writing this, so if the version is much newer, remind me to update this readme :)
|
||||

|
||||
Current version is 1.1 as of writing this, so if the version is much newer, remind me to update this readme :)
|
||||

|
||||
|
||||
## Dependencies
|
||||
ncurses
|
||||
cmake
|
||||
|
||||
## Building
|
||||
There is no release right now. There is only the debug build which will produce an executable called 'tester'.
|
||||
To build just run `make`.
|
||||
```
|
||||
mkdir build
|
||||
cd build
|
||||
cmake ..
|
||||
make
|
||||
```
|
||||
|
||||
## Installing
|
||||
I would not recommend installing at this time. There is no install target in the makefile.
|
||||
From within the build directory:
|
||||
```
|
||||
make install
|
||||
```
|
||||
|
||||
## More Screenshots
|
||||
Some test outputs on a file filled with laughing cat emojis
|
||||
|
||||
256 color:
|
||||
256 color:
|
||||

|
||||
|
||||
Truecolor (24 bit):
|
||||
Truecolor (24 bit):
|
||||

|
||||
|
||||
16 color (type that will work in a tty):
|
||||
16 color (type that will work in a tty):
|
||||

|
||||
|
||||
[1]: https://github.com/busyloop/lolcat
|
||||
|
||||
2
TODO
Normal file
2
TODO
Normal file
@@ -0,0 +1,2 @@
|
||||
move GNU cat logic out of printer class to make it more modular
|
||||
fix ^` not printing
|
||||
@@ -22,15 +22,6 @@
|
||||
#include <vector> //std::vector
|
||||
#include <cstddef> //size_t
|
||||
|
||||
struct cmd_options{
|
||||
const char* lopt;
|
||||
char sopt;
|
||||
const char* desc;
|
||||
};
|
||||
|
||||
extern const cmd_options cmd_arguments_list[];
|
||||
extern const size_t cmd_arguments_list_size;
|
||||
|
||||
|
||||
#define PRINT_LINE_NEVER 0
|
||||
#define PRINT_LINE_ALWAYS 1
|
||||
@@ -46,8 +37,8 @@ struct cmd_args{
|
||||
|
||||
//lolcat options
|
||||
long seed = 0;
|
||||
float freq = 0.2f;
|
||||
float spread = 0.3f;
|
||||
float freq = 0.3f;
|
||||
float spread = 0.4f;
|
||||
unsigned truecol:1;
|
||||
unsigned color:2;
|
||||
unsigned invert:1;
|
||||
@@ -58,6 +49,7 @@ struct cmd_args{
|
||||
unsigned squeeze:1;
|
||||
unsigned tabs:1;
|
||||
unsigned nonprinting:1;
|
||||
unsigned treatbinary:1;
|
||||
|
||||
//flags
|
||||
unsigned error:1;
|
||||
@@ -66,8 +58,20 @@ struct cmd_args{
|
||||
|
||||
cmd_args(void)noexcept;
|
||||
void clear_gnu_options(void);
|
||||
void set_nonprinting(bool = true);
|
||||
};
|
||||
|
||||
struct cmd_options{
|
||||
const char* lopt;
|
||||
char sopt;
|
||||
const char* desc;
|
||||
};
|
||||
|
||||
extern const cmd_options cmd_arguments_list[];
|
||||
extern const size_t cmd_arguments_list_size;
|
||||
|
||||
|
||||
|
||||
cmd_args process_cmd_args(int argc, char** argv);
|
||||
|
||||
#endif
|
||||
|
||||
@@ -96,9 +96,7 @@ auto printer_base<Derived>::print(const wchar_t* s)noexcept(noexcept(std::declva
|
||||
}
|
||||
template<class Derived>
|
||||
auto printer_base<Derived>::print(char s) -> Derived&{
|
||||
wchar_t tmp;
|
||||
mbstowcs(&tmp, &s, 1);
|
||||
return print(tmp);
|
||||
return print(static_cast<wchar_t>(s));
|
||||
}
|
||||
template<class Derived>
|
||||
auto printer_base<Derived>::print(const char* s) -> Derived&{
|
||||
|
||||
169
src/cmd.cpp
169
src/cmd.cpp
@@ -25,11 +25,14 @@
|
||||
#include <cstdlib> //atol
|
||||
|
||||
cmd_args::cmd_args(void)noexcept:
|
||||
truecol(0), color(0), number(0), ends(0), squeeze(0), tabs(0), nonprinting(0), error(0), usage(0), version(0){}
|
||||
truecol(0), color(0), invert(0), number(0), ends(0), squeeze(0), tabs(0), nonprinting(0), treatbinary(0), error(0), usage(0), version(0){}
|
||||
void cmd_args::clear_gnu_options(void){
|
||||
number = PRINT_LINE_NEVER;
|
||||
ends = squeeze = tabs = nonprinting = 0;
|
||||
}
|
||||
void cmd_args::set_nonprinting(bool i){
|
||||
nonprinting = treatbinary = i;
|
||||
}
|
||||
|
||||
static constexpr size_t constexpr_strlen(const char* str){
|
||||
size_t i = 0;
|
||||
@@ -60,6 +63,10 @@ template<const char* S1, const char* S2>
|
||||
struct concat_many_strs<S1,S2>{
|
||||
static constexpr const char* str = concat_strs<S1, S2>::str;
|
||||
};
|
||||
template<char... Cs>
|
||||
struct char_to_str{
|
||||
static constexpr const char str[sizeof...(Cs)+1] = {Cs..., '\0'};
|
||||
};
|
||||
|
||||
#define NO_LONG_OPTION nullptr
|
||||
#define REQ_INTEGER_ARG "=<i>"
|
||||
@@ -74,6 +81,7 @@ static constexpr const char* VT_LONG_OPTION = NO_LONG_OPTION;
|
||||
static constexpr const char SHOW_TABS_LONG_OPTION[] = "show-tabs";
|
||||
static constexpr const char* U_IGNORED_LONG_OPTION = NO_LONG_OPTION;
|
||||
static constexpr const char NONPRINTING_LONG_OPTION[] = "show-nonprinting";
|
||||
static constexpr const char BINARY_LONG_OPTION[] = "binary";
|
||||
static constexpr const char USAGE_LONG_OPTION[] = "help";
|
||||
static constexpr const char VERSION_LONG_OPTION[] = "version";
|
||||
static constexpr const char SEED_LONG_OPTION[] = "seed" REQ_INTEGER_ARG;
|
||||
@@ -88,64 +96,97 @@ static constexpr const char IGNORE_ANIMATE_LONG_OPTION[] = "animate";
|
||||
static constexpr const char IGNORE_DURATION_LONG_OPTION[] = "duration" REQ_INTEGER_ARG;
|
||||
static constexpr const char IGNORE_SPEED_LONG_OPTION[] = "speed" REQ_FLOAT_ARG;
|
||||
|
||||
#define NO_SHORT_OPTION ""
|
||||
static constexpr const char SHOW_ALL_SHORT_OPTION[] = "A";
|
||||
static constexpr const char NUMBER_NONBLANK_SHORT_OPTION[] = "b";
|
||||
static constexpr const char TRUECOLOR_SHORT_OPTION[] = "C";
|
||||
static constexpr const char VE_SHORT_OPTION[] = "e";
|
||||
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";
|
||||
static constexpr const char SQUEEZE_BLANKS_SHORT_OPTION[] = "s";
|
||||
static constexpr const char SEED_SHORT_OPTION[] = "S";
|
||||
static constexpr const char VT_SHORT_OPTION[] = "t";
|
||||
static constexpr const char SHOW_TABS_SHORT_OPTION[] = "T";
|
||||
static constexpr const char U_IGNORED_SHORT_OPTION[] = "u";
|
||||
static constexpr const char NONPRINTING_SHORT_OPTION[] = "v";
|
||||
#define NO_SHORT_OPTION 0
|
||||
static constexpr char SHOW_ALL_SHORT_OPTION = 'A';
|
||||
static constexpr char NUMBER_NONBLANK_SHORT_OPTION = 'b';
|
||||
static constexpr char BINARY_SHORT_OPTION = 'B';
|
||||
static constexpr char TRUECOLOR_SHORT_OPTION = 'C';
|
||||
static constexpr char VE_SHORT_OPTION = 'e';
|
||||
static constexpr char SHOW_ENDS_SHORT_OPTION = 'E';
|
||||
static constexpr char FORCE_COLOR_SHORT_OPTION = 'f';
|
||||
static constexpr char FREQ_SHORT_OPTION = 'F';
|
||||
static constexpr char USAGE_SHORT_OPTION = 'h';
|
||||
static constexpr char INVERT_SHORT_OPTION = 'i';
|
||||
static constexpr char NUMBER_LINES_SHORT_OPTION = 'n';
|
||||
static constexpr char DISABLE_COLOR_SHORT_OPTION = 'N';
|
||||
static constexpr char SPREAD_SHORT_OPTION = 'p';
|
||||
static constexpr char SQUEEZE_BLANKS_SHORT_OPTION = 's';
|
||||
static constexpr char SEED_SHORT_OPTION = 'S';
|
||||
static constexpr char VT_SHORT_OPTION = 't';
|
||||
static constexpr char SHOW_TABS_SHORT_OPTION = 'T';
|
||||
static constexpr char U_IGNORED_SHORT_OPTION = 'u';
|
||||
static constexpr char NONPRINTING_SHORT_OPTION = 'v';
|
||||
|
||||
static constexpr const char IGNORE_ANIMATE_SHORT_OPTION[] = "a";
|
||||
static constexpr const char IGNORE_DURATION_SHORT_OPTION[] = "d";
|
||||
static constexpr const char* IGNORE_SPEED_SHORT_OPTION = NO_SHORT_OPTION;
|
||||
static constexpr char IGNORE_ANIMATE_SHORT_OPTION = 'a';
|
||||
static constexpr char IGNORE_DURATION_SHORT_OPTION = 'd';
|
||||
static constexpr char IGNORE_SPEED_SHORT_OPTION = NO_SHORT_OPTION;
|
||||
|
||||
static constexpr const char* VERSION_SHORT_OPTION = NO_SHORT_OPTION;
|
||||
static constexpr char VERSION_SHORT_OPTION = NO_SHORT_OPTION;
|
||||
|
||||
#define NO_DESC nullptr
|
||||
static constexpr const char IGNORED_DESC[] = "Ignored for compatability";
|
||||
static constexpr const char EQUIV_DESC_BASE[] = "equivalent to -";
|
||||
static constexpr const char* SHOW_ALL_DESC = concat_many_strs<EQUIV_DESC_BASE,NONPRINTING_SHORT_OPTION,SHOW_ENDS_SHORT_OPTION,SHOW_TABS_SHORT_OPTION>::str;
|
||||
static constexpr const char* SHOW_ALL_DESC = concat_many_strs<EQUIV_DESC_BASE,char_to_str<NONPRINTING_SHORT_OPTION>::str,char_to_str<SHOW_ENDS_SHORT_OPTION>::str,char_to_str<SHOW_TABS_SHORT_OPTION>::str>::str;
|
||||
static constexpr const char NUMBER_NONBLANK_DESC_BASE[] = "number nonempty output lines, overrides -";
|
||||
static constexpr const char* NUMBER_NONBLANK_DESC = concat_many_strs<NUMBER_NONBLANK_DESC_BASE,SHOW_TABS_SHORT_OPTION>::str;
|
||||
static constexpr const char* VE_DESC = concat_many_strs<EQUIV_DESC_BASE,NONPRINTING_SHORT_OPTION,SHOW_ENDS_SHORT_OPTION>::str;
|
||||
static constexpr const char* NUMBER_NONBLANK_DESC = concat_many_strs<NUMBER_NONBLANK_DESC_BASE,char_to_str<SHOW_TABS_SHORT_OPTION>::str>::str;
|
||||
static constexpr const char* VE_DESC = concat_many_strs<EQUIV_DESC_BASE,char_to_str<NONPRINTING_SHORT_OPTION>::str,char_to_str<SHOW_ENDS_SHORT_OPTION>::str>::str;
|
||||
static constexpr const char SHOW_ENDS_DESC[] = "display $ at end of each line";
|
||||
static constexpr const char NUMBER_LINES_DESC[] = "number all output lines";
|
||||
static constexpr const char SQUEEZE_BLANKS_DESC[] = "suppress repeated empty output lines";
|
||||
static constexpr const char* VT_DESC = concat_many_strs<EQUIV_DESC_BASE,NONPRINTING_SHORT_OPTION,SHOW_TABS_SHORT_OPTION>::str;
|
||||
static constexpr const char* VT_DESC = concat_many_strs<EQUIV_DESC_BASE,char_to_str<NONPRINTING_SHORT_OPTION>::str,char_to_str<SHOW_TABS_SHORT_OPTION>::str>::str;
|
||||
static constexpr const char SHOW_TABS_DESC[] = "display TAB characters as ^I";
|
||||
static constexpr const char* U_IGNORED_DESC = IGNORED_DESC;
|
||||
static constexpr const char NONPRINTING_DESC[] = "should use ^ and M- notation, except for LFD and TAB (not supported as of now)";
|
||||
static constexpr const char BINARY_DESC[] = "treat FILE as a binary file\n";
|
||||
static constexpr const char NONPRINTING_DESC_BASE[] = "Use ^ and M- notation, except for LFD and TAB. Implies -";
|
||||
static constexpr const char* NONPRINTING_DESC = concat_many_strs<NONPRINTING_DESC_BASE,char_to_str<BINARY_SHORT_OPTION>::str,char_to_str<'\n'>::str>::str;
|
||||
static constexpr const char USAGE_DESC[] = "display this help and exit";
|
||||
static constexpr const char VERSION_DESC[] = "output version information and exit";
|
||||
static constexpr const char SEED_DESC[] = "Rainbow seed, 0 = random (default: 0)";
|
||||
static constexpr const char SPREAD_DESC[] = "Rainbow spread (default: Not yet decided)";
|
||||
static constexpr const char FREQ_DESC[] = "Rainbow frequency (default: Not yet decided)";
|
||||
static constexpr const char SPREAD_DESC[] = "Rainbow spread (default: 0.4)";
|
||||
static constexpr const char FREQ_DESC[] = "Rainbow frequency (default: 0.3)";
|
||||
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<DISABLE_COLOR_DESC_BASE,FORCE_COLOR_SHORT_OPTION>::str;
|
||||
static constexpr const char INVERT_DESC[] = "Change background color instead of foreground";
|
||||
static constexpr const char* DISABLE_COLOR_DESC = concat_many_strs<DISABLE_COLOR_DESC_BASE,char_to_str<FORCE_COLOR_SHORT_OPTION>::str>::str;
|
||||
static constexpr const char INVERT_DESC[] = "Change background color instead of foreground\n";
|
||||
|
||||
static constexpr const char* IGNORE_ANIMATE_DESC = IGNORED_DESC;
|
||||
static constexpr const char* IGNORE_DURATION_DESC = IGNORED_DESC;
|
||||
static constexpr const char* IGNORE_SPEED_DESC = IGNORED_DESC;
|
||||
|
||||
#define SHORT_OPT(x) (x##_SHORT_OPTION)[0]
|
||||
#define SHORT_OPT(x) (x##_SHORT_OPTION)
|
||||
#define OPTION(x) {x##_LONG_OPTION, SHORT_OPT(x), x##_DESC}
|
||||
|
||||
const cmd_options cmd_arguments_list[] = {
|
||||
OPTION(SHOW_ALL),
|
||||
OPTION(NUMBER_NONBLANK),
|
||||
OPTION(VE),
|
||||
OPTION(SHOW_ENDS),
|
||||
OPTION(NUMBER_LINES),
|
||||
OPTION(SQUEEZE_BLANKS),
|
||||
OPTION(VT),
|
||||
OPTION(SHOW_TABS),
|
||||
OPTION(U_IGNORED),
|
||||
OPTION(NONPRINTING),
|
||||
OPTION(BINARY),
|
||||
OPTION(SEED),
|
||||
OPTION(SPREAD),
|
||||
OPTION(FREQ),
|
||||
OPTION(TRUECOLOR),
|
||||
OPTION(FORCE_COLOR),
|
||||
OPTION(DISABLE_COLOR),
|
||||
OPTION(IGNORE_ANIMATE),
|
||||
OPTION(IGNORE_DURATION),
|
||||
OPTION(IGNORE_SPEED),
|
||||
OPTION(INVERT),
|
||||
OPTION(USAGE),
|
||||
OPTION(VERSION)
|
||||
};
|
||||
const size_t cmd_arguments_list_size = sizeof(cmd_arguments_list)/sizeof(cmd_arguments_list[0]);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
static constexpr bool is_integer(const char* s){
|
||||
if(*s != '-' && (*s < '0' || *s > '9')){
|
||||
@@ -188,10 +229,11 @@ static constexpr size_t strlen_pre_eq(const char* str){
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
#define CHECK_VALID_LONG_ARG(opt, off, arg, type) \
|
||||
{ \
|
||||
if(arg[off] != '=' || !is_##type(arg+off+1)){ \
|
||||
fwprintf(stderr, L"'--%.*s' requires an argument of type " #type "\n", off, opt); \
|
||||
fprintf(stderr, "'--%.*s' requires an argument of type " #type "\n", off, opt); \
|
||||
ret.error = 1; \
|
||||
break; \
|
||||
} \
|
||||
@@ -202,7 +244,7 @@ static constexpr size_t strlen_pre_eq(const char* str){
|
||||
#define CHECK_VALID_SHORT_ARG(opt, arg, type) \
|
||||
{ \
|
||||
if(next_arg == argc || !is_##type(arg)){ \
|
||||
fwprintf(stderr, L"'-%s' requires an argument of type " #type "\n", opt); \
|
||||
fprintf(stderr, "'-%c' requires an argument of type " #type "\n", opt); \
|
||||
ret.error = 1; \
|
||||
break; \
|
||||
} \
|
||||
@@ -234,13 +276,15 @@ cmd_args process_cmd_args(int argc, char** argv){
|
||||
for(size_t j = 1;j < arg_len;++j){
|
||||
switch(argv[i][j]){
|
||||
case SHORT_OPT(SHOW_ALL):
|
||||
ret.nonprinting = ret.ends = ret.tabs = 1;
|
||||
ret.set_nonprinting();
|
||||
ret.ends = ret.tabs = 1;
|
||||
break;
|
||||
case SHORT_OPT(NUMBER_NONBLANK):
|
||||
ret.number = PRINT_LINE_NONBLANK;
|
||||
break;
|
||||
case SHORT_OPT(VE):
|
||||
ret.nonprinting = ret.ends = 1;
|
||||
ret.set_nonprinting();
|
||||
ret.ends = 1;
|
||||
break;
|
||||
case SHORT_OPT(SHOW_ENDS):
|
||||
ret.ends = 1;
|
||||
@@ -253,6 +297,7 @@ cmd_args process_cmd_args(int argc, char** argv){
|
||||
ret.squeeze = 1;
|
||||
break;
|
||||
case SHORT_OPT(VT):
|
||||
ret.set_nonprinting();
|
||||
ret.nonprinting = ret.tabs = 1;
|
||||
break;
|
||||
case SHORT_OPT(SHOW_TABS):
|
||||
@@ -261,7 +306,10 @@ cmd_args process_cmd_args(int argc, char** argv){
|
||||
case SHORT_OPT(U_IGNORED):
|
||||
break;
|
||||
case SHORT_OPT(NONPRINTING):
|
||||
ret.nonprinting = 1;
|
||||
ret.set_nonprinting();
|
||||
break;
|
||||
case SHORT_OPT(BINARY):
|
||||
ret.treatbinary = 1;
|
||||
break;
|
||||
case SHORT_OPT(USAGE):
|
||||
ret.usage = 1;
|
||||
@@ -306,7 +354,7 @@ cmd_args process_cmd_args(int argc, char** argv){
|
||||
default:
|
||||
//keep parsing after error so we can still properly output requested color style
|
||||
ret.error = 1;
|
||||
fwprintf(stderr, L"Unrecognized option '-%c'\n", argv[i][j]);
|
||||
fprintf(stderr, "Unrecognized option '-%c'\n", argv[i][j]);
|
||||
};
|
||||
}
|
||||
i = next_arg-1;
|
||||
@@ -324,7 +372,9 @@ cmd_args process_cmd_args(int argc, char** argv){
|
||||
}else if(CHECK_LONG_OPTION(SHOW_TABS, arg)){
|
||||
ret.tabs = 1;
|
||||
}else if(CHECK_LONG_OPTION(NONPRINTING, arg)){
|
||||
ret.nonprinting = 1;
|
||||
ret.set_nonprinting();
|
||||
}else if(CHECK_LONG_OPTION(BINARY, arg)){
|
||||
ret.treatbinary = 1;
|
||||
}else if(CHECK_LONG_OPTION(USAGE, arg)){
|
||||
ret.usage = 1;
|
||||
}else if(CHECK_LONG_OPTION(VERSION, arg)){
|
||||
@@ -339,15 +389,15 @@ cmd_args process_cmd_args(int argc, char** argv){
|
||||
}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);
|
||||
constexpr int offset = strlen_pre_eq(SEED_LONG_OPTION);
|
||||
CHECK_VALID_LONG_INT_ARG(SEED, offset, arg);
|
||||
ret.seed = atol(arg+offset+1);
|
||||
}else if(CHECK_LONG_OPTION_WITH_ARG(SPREAD, arg)){
|
||||
constexpr size_t offset = strlen_pre_eq(SPREAD_LONG_OPTION);
|
||||
constexpr int offset = strlen_pre_eq(SPREAD_LONG_OPTION);
|
||||
CHECK_VALID_LONG_FLOAT_ARG(SPREAD, offset, arg);
|
||||
ret.spread = atof(arg+offset+1);
|
||||
}else if(CHECK_LONG_OPTION_WITH_ARG(FREQ, arg)){
|
||||
constexpr size_t offset = strlen_pre_eq(FREQ_LONG_OPTION);
|
||||
constexpr int offset = strlen_pre_eq(FREQ_LONG_OPTION);
|
||||
CHECK_VALID_LONG_FLOAT_ARG(FREQ, offset, arg);
|
||||
ret.freq = atof(arg+offset+1);
|
||||
}else if(CHECK_LONG_OPTION(IGNORE_ANIMATE, arg) ||
|
||||
@@ -357,7 +407,7 @@ cmd_args process_cmd_args(int argc, char** argv){
|
||||
;
|
||||
}else{
|
||||
ret.error = 1;
|
||||
fwprintf(stderr, L"Unrecognized option '%s'\n", argv[i]);
|
||||
fprintf(stderr, "Unrecognized option '%s'\n", argv[i]);
|
||||
}
|
||||
}else{
|
||||
ret.filenames.push_back(argv[i]);
|
||||
@@ -368,32 +418,3 @@ cmd_args process_cmd_args(int argc, char** argv){
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
const cmd_options cmd_arguments_list[] = {
|
||||
OPTION(SHOW_ALL),
|
||||
OPTION(NUMBER_NONBLANK),
|
||||
OPTION(VE),
|
||||
OPTION(SHOW_ENDS),
|
||||
OPTION(NUMBER_LINES),
|
||||
OPTION(SQUEEZE_BLANKS),
|
||||
OPTION(VT),
|
||||
OPTION(SHOW_TABS),
|
||||
OPTION(U_IGNORED),
|
||||
OPTION(NONPRINTING),
|
||||
{nullptr,0,nullptr}, //add newline to output
|
||||
OPTION(SEED),
|
||||
OPTION(SPREAD),
|
||||
OPTION(FREQ),
|
||||
OPTION(TRUECOLOR),
|
||||
OPTION(FORCE_COLOR),
|
||||
OPTION(DISABLE_COLOR),
|
||||
OPTION(IGNORE_ANIMATE),
|
||||
OPTION(IGNORE_DURATION),
|
||||
OPTION(IGNORE_SPEED),
|
||||
OPTION(INVERT),
|
||||
{nullptr,0,nullptr},
|
||||
OPTION(USAGE),
|
||||
OPTION(VERSION)
|
||||
};
|
||||
const size_t cmd_arguments_list_size = sizeof(cmd_arguments_list)/sizeof(cmd_arguments_list[0]);
|
||||
|
||||
|
||||
167
src/roflcat.cpp
167
src/roflcat.cpp
@@ -33,8 +33,11 @@
|
||||
#include <cstddef> //size_t
|
||||
#include <chrono> //std::chrono::*
|
||||
#include <cstdlib> //srand
|
||||
#include <string> //char_traits
|
||||
#include <sys/types.h> //struct stat
|
||||
#include <sys/stat.h> //struct stat
|
||||
|
||||
constexpr const char version_string[] = "roflcat version 1.0.4";
|
||||
constexpr const char version_string[] = "roflcat version 1.1";
|
||||
|
||||
static constexpr size_t constexpr_strlen(const char* str){
|
||||
size_t i = 0;
|
||||
@@ -50,7 +53,7 @@ static constexpr size_t constexpr_strlen(const char* str){
|
||||
static int detect_term_colors(void){
|
||||
int term_colors = 16;
|
||||
if(setupterm(NULL, fileno(stdout), NULL) == ERR){
|
||||
fwprintf(stderr, L"could not set up term\n");
|
||||
fprintf(stderr, "could not set up term\n");
|
||||
}else{
|
||||
term_colors = tigetnum("colors");
|
||||
if(term_colors < 0){
|
||||
@@ -91,6 +94,7 @@ constexpr void print_usage(Printer&& p){
|
||||
p.print(L'\n');
|
||||
}
|
||||
p.print(L"\nroflcat Copyright (C) 2019 rexy712\n");
|
||||
p.print(L"Source code can be found at https://gitlab.com/rexy712/roflcat\n");
|
||||
p.print(L"This program comes with ABSOLUTELY NO WARRANTY\n");
|
||||
p.print(L"This is free software, and you are welcome to redistribute it\n");
|
||||
p.print(L"under certain conditions; see the GNU GPLv3 for details.\n");
|
||||
@@ -103,8 +107,133 @@ constexpr void print_version(Printer&& p){
|
||||
p.reset();
|
||||
}
|
||||
|
||||
void to_caret_notation(int in, char* dest){
|
||||
dest[0] = '^';
|
||||
dest[1] = in ^ 0x40;
|
||||
dest[2] = 0;
|
||||
}
|
||||
void to_mdash_notation(int in, char* dest){
|
||||
int corin = in & 0x7F;
|
||||
dest[0] = 'M';
|
||||
dest[1] = '-';
|
||||
if(corin > 32 && corin < 127){
|
||||
dest[2] = corin;
|
||||
dest[3] = 0;
|
||||
}else{
|
||||
char tmp[3];
|
||||
to_caret_notation(corin, tmp);
|
||||
dest[2] = tmp[0];
|
||||
dest[3] = tmp[1];
|
||||
dest[4] = 0;
|
||||
}
|
||||
}
|
||||
void nonprinting_notation(int in, char* dest){
|
||||
if(in & 0x80){
|
||||
to_mdash_notation(in, dest);
|
||||
}else if(in == '\n' || in == '\t' || (in > 31 && in < 127)){
|
||||
dest[0] = in;
|
||||
dest[1] = 0;
|
||||
}else{
|
||||
to_caret_notation(in, dest);
|
||||
}
|
||||
}
|
||||
|
||||
bool is_directory(const char* file){
|
||||
struct stat st;
|
||||
if(stat(file, &st) != 0){
|
||||
return false;
|
||||
}
|
||||
return S_ISDIR(st.st_mode);
|
||||
}
|
||||
bool file_exists(const char* file){
|
||||
struct stat st;
|
||||
return stat(file, &st) == 0;
|
||||
}
|
||||
FILE* open_file(const char* file, const char* mode){
|
||||
if(is_directory(file)){
|
||||
fflush(stdout);
|
||||
fprintf(stderr, "Unable to open file \"%s\": Is a directory \n", file);
|
||||
return nullptr;
|
||||
}
|
||||
if(!file_exists(file)){
|
||||
fflush(stdout);
|
||||
fprintf(stderr, "Unable to open file \"%s\": No such file\n", file);
|
||||
return nullptr;
|
||||
}
|
||||
FILE* fp = fopen(file, mode);
|
||||
if(!fp){
|
||||
fflush(stdout);
|
||||
fprintf(stderr, "Unable to open file for reading: \"%s\"\n", file);
|
||||
}
|
||||
return fp;
|
||||
}
|
||||
|
||||
template<class T, class Printer, class Func>
|
||||
inline void do_stdin(Printer&& p, Func&& f){
|
||||
for(T in;(in = f(stdin)) != std::char_traits<T>::eof();){
|
||||
p.print(in);
|
||||
if(in == '\n')
|
||||
p.reset();
|
||||
}
|
||||
clearerr(stdin);
|
||||
}
|
||||
//Use the given type of printer to output the contents of files and/or stdin
|
||||
template<class Printer>
|
||||
int real_print_files(const cmd_args& args){
|
||||
int ret = 0;
|
||||
Printer p(args);
|
||||
for(size_t i = 0;i < args.filenames.size();++i){
|
||||
if(!strcmp(args.filenames[i], "-")){ //stdin
|
||||
|
||||
if(args.treatbinary){
|
||||
//Don't check if buf is empty because that's not how GNU cat handles Ctrl+D in middle of line
|
||||
for(int in;(in = fgetc(stdin)) != EOF;){
|
||||
p.print(static_cast<char>(in));
|
||||
if(in == L'\n') //Only reset on newline to save print overhead
|
||||
p.reset();
|
||||
}
|
||||
}else{
|
||||
for(wint_t in;(in = fgetwc(stdin)) != WEOF;){
|
||||
p.print(static_cast<wchar_t>(in));
|
||||
if(in == L'\n')
|
||||
p.reset();
|
||||
}
|
||||
}
|
||||
clearerr(stdin);
|
||||
|
||||
}else{ //everything besides stdin
|
||||
|
||||
FILE* fp = open_file(args.filenames[i], "r");
|
||||
if(!fp){
|
||||
ret = 2;
|
||||
continue;
|
||||
}
|
||||
if(args.treatbinary){
|
||||
if(args.nonprinting){
|
||||
for(int in;(in = fgetc(fp)) != EOF;){
|
||||
char tmp[5];
|
||||
nonprinting_notation(in, tmp);
|
||||
p.print(tmp);
|
||||
}
|
||||
}else{
|
||||
for(int in;(in = fgetc(fp)) != EOF;)
|
||||
p.print(static_cast<char>(in));
|
||||
}
|
||||
}else{
|
||||
//set to wide character mode before anything
|
||||
fwide(fp, 1);
|
||||
for(wint_t in;(in = fgetwc(fp)) != WEOF;)
|
||||
p.print(static_cast<wchar_t>(in));
|
||||
}
|
||||
p.reset();
|
||||
fclose(fp);
|
||||
|
||||
}
|
||||
}
|
||||
p.reset();
|
||||
return ret;
|
||||
}
|
||||
template<class Printer>
|
||||
int print_files(cmd_args& args){
|
||||
if(args.usage){
|
||||
args.clear_gnu_options();
|
||||
@@ -115,37 +244,10 @@ int print_files(cmd_args& args){
|
||||
print_version(Printer{args});
|
||||
return 0;
|
||||
}
|
||||
int ret = 0;
|
||||
Printer p(args);
|
||||
for(size_t i = 0;i < args.filenames.size();++i){
|
||||
if(!strcmp(args.filenames[i], "-")){ //stdin
|
||||
|
||||
//Don't check if buf is empty because that's not how GNU cat handles Ctrl+D in middle of line
|
||||
for(wint_t in;(in = fgetwc(stdin)) != WEOF;){
|
||||
p.print(static_cast<wchar_t>(in));
|
||||
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){
|
||||
fflush(stdout); //force color update before error
|
||||
fwprintf(stderr, L"Unable to open file %s\n", args.filenames[i]);
|
||||
ret = 2;
|
||||
continue;
|
||||
}
|
||||
//set to wide character mode before anything
|
||||
fwide(fp, 1);
|
||||
for(wint_t in;(in = fgetwc(fp)) != WEOF;)
|
||||
p.print(static_cast<wchar_t>(in));
|
||||
p.reset();
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
p.reset();
|
||||
return ret;
|
||||
return real_print_files<Printer>(args);
|
||||
}
|
||||
|
||||
auto get_time(void){
|
||||
auto time = std::chrono::high_resolution_clock::now();
|
||||
auto eptime = time.time_since_epoch();
|
||||
@@ -159,7 +261,7 @@ int main(int argc, char** argv){
|
||||
int avail_colors = detect_term_colors();
|
||||
|
||||
if(args.error){
|
||||
fwprintf(stderr, L"Try '%s --help' for more information.\n", argv[0]);
|
||||
fprintf(stderr, "Try '%s --help' for more information.\n", argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -174,6 +276,5 @@ int main(int argc, char** argv){
|
||||
}else if(avail_colors == 256){
|
||||
return print_files<basic_color_printer<256>>(args);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user