Initial commit
This commit is contained in:
commit
2f168b8b4e
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
strlen
|
||||
*.o
|
||||
19
makefile
Normal file
19
makefile
Normal file
@ -0,0 +1,19 @@
|
||||
.PHONY: all
|
||||
all: strlen
|
||||
|
||||
strlen: src/strlen.cpp
|
||||
g++ -o strlen -O2 -Wall -Wextra -pedantic -std=c++17 src/strlen.cpp
|
||||
strip --strip-all strlen
|
||||
|
||||
|
||||
.PHONY: install
|
||||
install:
|
||||
install -m755 -s strlen "$(DESTDIR)/usr/bin/"
|
||||
|
||||
.PHONY: uninstall
|
||||
uninstall:
|
||||
rm "$(DESTDIR)/usr/bin/strlen"
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm -f strlen
|
||||
195
src/strlen.cpp
Normal file
195
src/strlen.cpp
Normal file
@ -0,0 +1,195 @@
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <locale.h>
|
||||
#include <cwchar>
|
||||
#include <cstdlib>
|
||||
#include <vector>
|
||||
|
||||
namespace cmd{
|
||||
struct flags{
|
||||
int retval;
|
||||
unsigned abort:1;
|
||||
unsigned cumulative:1;
|
||||
unsigned ignorenl:1;
|
||||
std::vector<char*> args;
|
||||
};
|
||||
|
||||
struct options{
|
||||
const char* lopt;
|
||||
char sopt;
|
||||
const char* desc;
|
||||
int (*func)(int, char**, int, flags&);
|
||||
};
|
||||
}
|
||||
|
||||
static cmd::options cmd_options[] = {
|
||||
{"--cumulative", 'c', "suppress normal output and sum all the lengths together", [](int, char**, int, cmd::flags& f)->int{f.cumulative = 1;return 0;}},
|
||||
{"--ignorenewline", 'n', "do not count newlines toward the character count", [](int, char**, int, cmd::flags& f)->int{f.ignorenl = 1;return 0;}},
|
||||
{"--help", 'h', "print this help message and exit", [](int, char**, int, cmd::flags& f)->int{f.abort = 1;return 1;}}
|
||||
};
|
||||
|
||||
//print usage message
|
||||
[[noreturn]]
|
||||
void usage(char* programname, int code){
|
||||
wprintf(L"Usage: %s [OPTION]... [STRING]...\n", programname);
|
||||
wprintf(L"Print the length of STRING(s) to standard output\n");
|
||||
wprintf(L"\n");
|
||||
wprintf(L"With no STRING, or when STRING is -, read standard input.\n");
|
||||
wprintf(L"\n");
|
||||
|
||||
for(size_t i = 0;i < sizeof(cmd_options)/sizeof(cmd_options[0]);++i){
|
||||
size_t spacing = 20;
|
||||
spacing -= strlen(cmd_options[i].lopt);
|
||||
wprintf(L" ");
|
||||
wprintf(L"-%c, %s", cmd_options[i].sopt, cmd_options[i].lopt);
|
||||
wprintf(L"%*s", spacing, "");
|
||||
wprintf(L"%s\n", cmd_options[i].desc);
|
||||
}
|
||||
|
||||
wprintf(L"\n");
|
||||
wprintf(L"strlen Copyright (C) 2019 rexy712\n");
|
||||
wprintf(L"This program comes with ABSOLUTELY NO WARRANTY\n");
|
||||
wprintf(L"This is free software, and you are welcome to redistribute it\n");
|
||||
wprintf(L"under certain conditions; see the GNU GPLv3 for details.\n");
|
||||
wprintf(L"A copy of the GPLv3 is available with the source in the file 'LICENSE'\n");
|
||||
|
||||
exit(code);
|
||||
}
|
||||
|
||||
namespace cmd{
|
||||
//Turn command line arguments into flags and individual strings
|
||||
flags handle_args(int argc, char** argv){
|
||||
flags return_val = {};
|
||||
bool ignore_args = false;
|
||||
|
||||
for(int i = 1;i < argc;++i){
|
||||
//non option arguments
|
||||
if(argv[i][0] != '-' || ignore_args){
|
||||
return_val.args.push_back(argv[i]);
|
||||
continue;
|
||||
}
|
||||
if(argv[i][1] == 0){
|
||||
return_val.args.push_back(argv[i]);
|
||||
continue;
|
||||
}
|
||||
//everything after '--' is treated as not an argument
|
||||
if(argv[i][1] == '-' && argv[i][2] == 0){
|
||||
ignore_args = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t arglen = strlen(argv[i]);
|
||||
//handle short options
|
||||
if(argv[i][1] != '-'){
|
||||
for(size_t j = 1;j < arglen;++j){
|
||||
bool found = false;
|
||||
for(size_t k = 0;k < sizeof(cmd_options)/sizeof(cmd_options[0]);++k){
|
||||
if(argv[i][j] == cmd_options[k].sopt){
|
||||
found = true;
|
||||
return_val.retval = cmd_options[k].func(argc, argv, i, return_val);
|
||||
if(return_val.retval)
|
||||
return return_val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found){
|
||||
fwprintf(stderr, L"Unrecognized argument -%c\n", argv[i][j]);
|
||||
return_val.abort = 1;
|
||||
return_val.retval = -1;
|
||||
return return_val;
|
||||
}
|
||||
}
|
||||
//handle long options
|
||||
}else{
|
||||
bool found = false;
|
||||
for(size_t j = 0;j < sizeof(cmd_options)/sizeof(cmd_options[0]);++j){
|
||||
if(!strcmp(argv[i], cmd_options[j].lopt)){
|
||||
found = true;
|
||||
return_val.retval = cmd_options[j].func(argc, argv, i, return_val);
|
||||
if(return_val.retval)
|
||||
return return_val;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!found){
|
||||
fwprintf(stderr, L"Unrecognized argument %s\n", argv[i]);
|
||||
return_val.abort = 1;
|
||||
return_val.retval = -1;
|
||||
return return_val;
|
||||
}
|
||||
}
|
||||
}
|
||||
return return_val;
|
||||
}
|
||||
}
|
||||
|
||||
//handle user input or piped input
|
||||
int do_stdin(bool ignore_newlines){
|
||||
int len = 0;
|
||||
if(feof(stdin)){
|
||||
return -1;
|
||||
}
|
||||
for(wint_t in;(in = fgetwc(stdin)) != WEOF;++len){
|
||||
if(in == L'\n'){
|
||||
if(!ignore_newlines) ++len;
|
||||
return len;
|
||||
}
|
||||
}
|
||||
if(feof(stdin) && !len)
|
||||
return -1;
|
||||
return len;
|
||||
}
|
||||
|
||||
//Sum of all strlens
|
||||
int do_cumulative(const cmd::flags& flags){
|
||||
int total = 0;
|
||||
if(flags.args.size() == 0){
|
||||
for(int len = 0;(len = do_stdin(flags.ignorenl)) >= 0;)
|
||||
total += len;
|
||||
wprintf(L"%d\n", total);
|
||||
return 0;
|
||||
}
|
||||
for(size_t i = 0;i < flags.args.size();++i){
|
||||
if(!strcmp(flags.args[i], "-")){
|
||||
for(int len;(len = do_stdin(flags.ignorenl)) >= 0;){
|
||||
total += len;
|
||||
}
|
||||
}else{
|
||||
total += strlen(flags.args[i]);
|
||||
}
|
||||
}
|
||||
wprintf(L"%d\n", total);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Non cumulative
|
||||
int do_basic(const cmd::flags& flags){
|
||||
if(flags.args.size() == 0){
|
||||
for(int len = 0;(len = do_stdin(flags.ignorenl)) >= 0;)
|
||||
wprintf(L"%d\n", len);
|
||||
return 0;
|
||||
}
|
||||
for(size_t i = 0;i < flags.args.size();++i){
|
||||
if(!strcmp(flags.args[i], "-")){
|
||||
for(int len;(len = do_stdin(flags.ignorenl)) >= 0;){
|
||||
wprintf(L"%d\n", len);
|
||||
}
|
||||
}else{
|
||||
wprintf(L"%d\n", strlen(flags.args[i]));
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int main(int argc, char** argv){
|
||||
setlocale(LC_ALL, "");
|
||||
|
||||
cmd::flags flags = cmd::handle_args(argc, argv);
|
||||
if(flags.abort)
|
||||
usage(argv[0], flags.retval);
|
||||
|
||||
if(flags.cumulative)
|
||||
return do_cumulative(flags);
|
||||
else
|
||||
return do_basic(flags);
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user