pwg – a password generator

pwg – a password generator

@Def(| c++ -x c++ -o pwg -)
@put(parts)
@end(| c++ -x c++ -o pwg -)
@def(parts)
@put(includes)
@end(parts)
@add(parts)
@put(globals)
@end(parts)
@add(parts)
int main(int argc, char *argv[]) {
@put(main)
}
@end(parts)
@def(main)
{ @put(unit-tests); }
@end(main)
@add(main)
@put(state);
@put(process args);
@end(main)
@def(includes)
#include <string>
#include <iostream>
@end(includes)
@add(main)
std::string pw;
@put(generate pw);
std::cout << pw << '\n';
@end(main)
@def(state)
int upper_count = 3;
std::string upper_set {
"ABCDEFGHIJKLMNOPQRSTUVWXYZ"
};
@end(state)
@add(includes)
#include <random>
@end(includes)
@def(globals)
using Uniform =
std::uniform_int_distribution<
int
>;
@end(globals)
@add(globals)
template<typename RE>
std::string random_select(
const std::string &source,
int count, RE &re
) {
std::string result;
@put(random select);
return result;
}
@end(globals)
@def(unit-tests)
using TestEngine =
std::linear_congruential_engine<
unsigned, 1, 0, 0x7ff
>;
@end(unit-tests)
@add(includes)
#include <exception>
@end(includes)
@add(unit-tests) {
TestEngine te { 0 };
if (
random_select("abc", 4, te) !=
"aaaa"
) {
throw std::logic_error(
"random select"
);
}
} @end(unit-tests)
@def(random select)
int max = source.size() - 1;
if (max < 0) {
throw std::invalid_argument(
"no chars"
);
}
Uniform d { 0, max };
for (int i = 0; i < count; ++i) {
result += source[d(re)];
}
@end(random select)
@add(state)
int seed = (std::random_device {})();
@end(state)
@def(generate pw)
std::mt19937 re { seed };
@end(generate pw)
@add(generate pw)
pw += random_select(
upper_set, upper_count, re
);
@end(generate pw)
@add(state)
int lower_count = 3;
std::string lower_set {
"abcdefghijklmnopqrstuvwxyz"
};
@end(state)
@add(generate pw)
pw += random_select(
lower_set, lower_count, re
);
@end(generate pw)
@add(generate pw)
@put(add other chars);
@put(shuffle pw);
@end(generate pw)
@add(includes)
#include <algorithm>
@end(includes)
@def(shuffle pw)
std::random_shuffle(
pw.begin(), pw.end()
);
@end(shuffle pw)
@add(state)
int digit_count = 2;
std::string digit_set {
"0123456789"
};
@end(state)
@def(add other chars)
pw += random_select(
digit_set, digit_count, re
);
@end(add other chars)
@add(state)
int special_count = 2;
std::string special_set {
".,:;!?+-*/[](){}"
};
@end(state)
@add(add other chars)
pw += random_select(
special_set, special_count, re
);
@end(add other chars)
@add(globals)
int to_int(
const std::string &s, int d
) {
try {
d = std::stoi(s);
}
catch (...) {
@put(to int err msg);
}
return d;
}
@end(globals)
@def(to int err msg)
std::cerr << "Can't convert `" <<
s << "` to integer; " <<
"will use " << d <<
" instead.\n";
@end(to int err msg)
@def(process args)
if (argc > 1) {
upper_count = to_int(
argv[1], upper_count
);
}
@end(process args)
@add(process args)
if (argc > 2) {
lower_count = to_int(
argv[2], lower_count
);
}
@end(process args)
@add(process args)
if (argc > 3) {
digit_count = to_int(
argv[3], digit_count
);
}
@end(process args)
@add(process args)
if (argc > 4) {
special_count = to_int(
argv[4], special_count
);
}
@end(process args)
@add(process args)
if (argc > 5) {
std::string s { argv[5] };
if (s.size()) {
special_set = argv[5];
} else {
std::cerr << "Specials are "
"empty; will use `" <<
special_set <<
"` instead.\n";
}
}
@end(process args)
@add(process args)
if (argc > 6) {
seed = to_int(argv[6], seed);
}
@end(process args)