Initial commit

This commit is contained in:
Rexy712 2019-05-05 01:44:17 -07:00
commit 2f168b8b4e
3 changed files with 216 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
strlen
*.o

19
makefile Normal file
View 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
View 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);
}