This commit is contained in:
anon 2023-06-12 15:38:07 +02:00
commit 0d60fb0377
11 changed files with 192 additions and 0 deletions

3
.gitignore vendored Normal file

@ -0,0 +1,3 @@
**/*.out
out.d/*
tests/*.cpp

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

@ -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

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

@ -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

@ -0,0 +1,2 @@
argv['d'] = "";
setopt("i:do:", argv);

2
tests/test3.cpp.part Normal file

@ -0,0 +1,2 @@
argv['d'] = "";
setopt(":-d", argv);

2
tests/test4.cpp.part Normal file

@ -0,0 +1,2 @@
argv['d'] = "";
setopt("d:", argv);

3
tests/test5.cpp.part Normal file

@ -0,0 +1,3 @@
argv['d'] = "";
argv['k'] = "unexpected_arg";
setopt("d", argv);

@ -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;
}