commit 0d60fb03774bdf0e0a0bfa8d96a73d5edfd61812
Author: anon <anon@anon.anon>
Date:   Mon Jun 12 15:38:07 2023 +0200

    init

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..5411a7d
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,3 @@
+**/*.out
+out.d/*
+tests/*.cpp
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..e801bdf
--- /dev/null
+++ b/Makefile
@@ -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/*
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..747abd1
--- /dev/null
+++ b/README.md
@@ -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 [...]
diff --git a/out.d/.placeholder b/out.d/.placeholder
new file mode 100644
index 0000000..e69de29
diff --git a/setopt.hpp b/setopt.hpp
new file mode 100644
index 0000000..bbd5104
--- /dev/null
+++ b/setopt.hpp
@@ -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; }
diff --git a/tests/test1.cpp.part b/tests/test1.cpp.part
new file mode 100644
index 0000000..24497bb
--- /dev/null
+++ b/tests/test1.cpp.part
@@ -0,0 +1,4 @@
+	argv['d'] = "";
+	argv['i'] = "input.txt";
+	argv['o'] = "output.txt";
+	setopt("i:do:", argv);
diff --git a/tests/test2.cpp.part b/tests/test2.cpp.part
new file mode 100644
index 0000000..c110387
--- /dev/null
+++ b/tests/test2.cpp.part
@@ -0,0 +1,2 @@
+	argv['d'] = "";
+	setopt("i:do:", argv);
diff --git a/tests/test3.cpp.part b/tests/test3.cpp.part
new file mode 100644
index 0000000..725b07a
--- /dev/null
+++ b/tests/test3.cpp.part
@@ -0,0 +1,2 @@
+	argv['d'] = "";
+	setopt(":-d", argv);
diff --git a/tests/test4.cpp.part b/tests/test4.cpp.part
new file mode 100644
index 0000000..1184104
--- /dev/null
+++ b/tests/test4.cpp.part
@@ -0,0 +1,2 @@
+	argv['d'] = "";
+	setopt("d:", argv);
diff --git a/tests/test5.cpp.part b/tests/test5.cpp.part
new file mode 100644
index 0000000..124d497
--- /dev/null
+++ b/tests/test5.cpp.part
@@ -0,0 +1,3 @@
+	argv['d'] = "";
+	argv['k'] = "unexpected_arg";
+	setopt("d", argv);
diff --git a/tests/test_template.cpp.m4 b/tests/test_template.cpp.m4
new file mode 100644
index 0000000..e2edb40
--- /dev/null
+++ b/tests/test_template.cpp.m4
@@ -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;
+}