init
This commit is contained in:
commit
0d60fb0377
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
**/*.out
|
||||
out.d/*
|
||||
tests/*.cpp
|
24
Makefile
Normal file
24
Makefile
Normal file
@ -0,0 +1,24 @@
|
||||
main:
|
||||
@-echo pass
|
||||
|
||||
test: test_template test_compile
|
||||
|
||||
run_test:
|
||||
@-for i in out.d/test*; do\
|
||||
./$$i; \
|
||||
done
|
||||
|
||||
test_template:
|
||||
cd tests/; \
|
||||
for i in *.cpp.part; do \
|
||||
m4 -Dtest=$$i test_template.cpp.m4 > $$(basename --suffix=".part" $$i); \
|
||||
done
|
||||
|
||||
test_compile:
|
||||
for i in tests/*.cpp; do \
|
||||
g++ -I $$(realpath .) $$i -o out.d/$$(basename $$i); \
|
||||
done
|
||||
|
||||
clean:
|
||||
rm tests/*.cpp
|
||||
rm out.d/*
|
34
README.md
Normal file
34
README.md
Normal file
@ -0,0 +1,34 @@
|
||||
# Setopt
|
||||
The reverse of getopt. It is standard to create a command from an internal state (object). It is a replacement for usual string concatenation techniques, providing argument order consistency and less bug-prone error handling.
|
||||
|
||||
## Docs
|
||||
### C
|
||||
Implemented as a header only library.
|
||||
|
||||
#include "setopt.h"
|
||||
|
||||
/* Struct to define long option - identifier pairs + flags;
|
||||
Straight from getopt
|
||||
*/
|
||||
struct option {
|
||||
const char *name;
|
||||
int has_arg;
|
||||
int *flag;
|
||||
int val;
|
||||
};
|
||||
|
||||
int optc, // number of arguments successfuly added
|
||||
reset on each invocation
|
||||
optred, /* not implemented */
|
||||
opterrno; // non zero if setopt encountered an error
|
||||
must be reset manually
|
||||
|
||||
char* setopt(const char* optstring, std::unordered_map<char, std::string> argv);
|
||||
char* setopt_long(char* optstring, map<string, string> argv, map<string, string> argv_long); /* Not implemented */
|
||||
char* setopt_long_only(char* optstring, map<string, string> argv_long); /* Not implemented */
|
||||
|
||||
|
||||
|
||||
**optstring:** Complies with GNU getopt's optstring. That is:
|
||||
|
||||
optstring is a string containing the legitimate option characters. A legitimate option character is any visible one byte ascii(7) character (for which isgraph(3) would return nonzero) that is not '-', ':', or ';'. If such a character is followed by a colon, the option requires an argument [...] Two colons mean an option takes an optional arg [...]
|
0
out.d/.placeholder
Normal file
0
out.d/.placeholder
Normal file
105
setopt.hpp
Normal file
105
setopt.hpp
Normal file
@ -0,0 +1,105 @@
|
||||
#pragma once
|
||||
|
||||
/*
|
||||
TODO:
|
||||
- implement setopt_long and setopt_long_only
|
||||
- add support repeated options
|
||||
- add support for embeding format strings
|
||||
*/
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
|
||||
|
||||
#define OPTPREFIX "-"
|
||||
#define OPTLONGPREFIX "--"
|
||||
#define OPTGAP " "
|
||||
|
||||
enum {
|
||||
SETOPTINVALIDOPTSTRING = 1,
|
||||
SETOPTMISSINGREQUIRED,
|
||||
SETOPTUNKNOWNOPT
|
||||
};
|
||||
|
||||
struct option {
|
||||
const char *name;
|
||||
int has_arg;
|
||||
int *flag;
|
||||
int val;
|
||||
};
|
||||
|
||||
enum {
|
||||
no_argument = 0,
|
||||
required_argument = 1,
|
||||
optional_argument = 2
|
||||
};
|
||||
|
||||
int optc, optred, opterrno = 0;
|
||||
|
||||
static inline void setopt_init(){
|
||||
optc = 0;
|
||||
}
|
||||
|
||||
char* setopt(const char* optstring, std::unordered_map<char, std::string> argv){
|
||||
setopt_init();
|
||||
|
||||
std::string rs;
|
||||
|
||||
for(const char* i = optstring; *i; i++){
|
||||
if(not isgraph(*i) or
|
||||
*i == '-' or
|
||||
*i == ':' or
|
||||
*i == ';'
|
||||
){
|
||||
opterrno = SETOPTINVALIDOPTSTRING;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto h = argv.find(*i);
|
||||
if(h != argv.end()){
|
||||
const char &opt = h->first;
|
||||
const std::string &optarg = h->second;
|
||||
rs += OPTGAP;
|
||||
rs += OPTPREFIX;
|
||||
rs += opt;
|
||||
++optc;
|
||||
if(*(i+1) == ':'){
|
||||
if(optarg != ""){
|
||||
rs += OPTGAP;
|
||||
rs += optarg;
|
||||
}else if(*(i+2) == ':'){
|
||||
++i;
|
||||
}else{
|
||||
opterrno = SETOPTMISSINGREQUIRED;
|
||||
}
|
||||
++i;
|
||||
}
|
||||
argv.erase(h);
|
||||
}else{
|
||||
for(int j = 0; j < 2; j++){
|
||||
if(*(i+1) == ':'){
|
||||
++i;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(argv.size()){
|
||||
opterrno = SETOPTUNKNOWNOPT;
|
||||
}
|
||||
|
||||
char* r;
|
||||
if(rs.size()){
|
||||
r = new char[rs.size()-1];
|
||||
strcpy(r, rs.c_str()+sizeof(OPTGAP)-1);
|
||||
}else{
|
||||
r = new char[1];
|
||||
r[0] = '\00';
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
char* setopt_long(const char* optstring, std::unordered_map<std::string, std::string> argv, const struct option* longopts){ return NULL; }
|
||||
char* setopt_long_only(const char* optstring, std::unordered_map<std::string, std::string> argv, const struct option* longopts){ return NULL; }
|
4
tests/test1.cpp.part
Normal file
4
tests/test1.cpp.part
Normal file
@ -0,0 +1,4 @@
|
||||
argv['d'] = "";
|
||||
argv['i'] = "input.txt";
|
||||
argv['o'] = "output.txt";
|
||||
setopt("i:do:", argv);
|
2
tests/test2.cpp.part
Normal file
2
tests/test2.cpp.part
Normal file
@ -0,0 +1,2 @@
|
||||
argv['d'] = "";
|
||||
setopt("i:do:", argv);
|
2
tests/test3.cpp.part
Normal file
2
tests/test3.cpp.part
Normal file
@ -0,0 +1,2 @@
|
||||
argv['d'] = "";
|
||||
setopt(":-d", argv);
|
2
tests/test4.cpp.part
Normal file
2
tests/test4.cpp.part
Normal file
@ -0,0 +1,2 @@
|
||||
argv['d'] = "";
|
||||
setopt("d:", argv);
|
3
tests/test5.cpp.part
Normal file
3
tests/test5.cpp.part
Normal file
@ -0,0 +1,3 @@
|
||||
argv['d'] = "";
|
||||
argv['k'] = "unexpected_arg";
|
||||
setopt("d", argv);
|
13
tests/test_template.cpp.m4
Normal file
13
tests/test_template.cpp.m4
Normal file
@ -0,0 +1,13 @@
|
||||
#include <stdio.h>
|
||||
#include <unordered_map>
|
||||
#include "setopt.hpp"
|
||||
|
||||
using namespace std;
|
||||
|
||||
signed main(){
|
||||
opterrno = 0;
|
||||
std::unordered_map<char, std::string> argv;
|
||||
include(test)
|
||||
printf("%d %d\n", optc, opterrno);
|
||||
return opterrno;
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user