a QR code generator for the command line
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

148 lines
3.6 KiB

#include <memory>
#include <getopt.h>
#include <iostream>
#include <sstream>
#include "QR.hpp"
#define UNUSED(var) (void) var;
// Version is injected through cmake
constexpr const char* VERSION = "@qr_VERSION@";
void printHelp() {
std::string helpText = R"EOF(
(C) 2023, MikO <miko@massivedynamic.eu>
a tool for generating QR codes
Released under MIT license.
Usage:
-f --format output file format. can be one of "cli, png, svg"
-h --help show this help
-i --input take data from this argument instead of stdin
-o --output output file name
-s --size desired output file size in pixels
-t --type output QR code type. can be one of "small, medium, large"
In pixel based renderers (i.e. PNG), the output size may not be exactly as
specified but be the nearest multiple of the actual cell size for the QR code.
)EOF";
std::cout << "qr " << VERSION;
std::cout << helpText << std::endl;
}
int main(int argc, char* argv[]) {
if (argc < 1) {
printHelp();
exit(1);
}
const option options[] = {
{"help", no_argument, nullptr, 'h'},
{"input", required_argument, nullptr, 'i'},
{"output", required_argument, nullptr, 'o'},
{"size", required_argument, nullptr, 's'},
{"type", required_argument, nullptr, 't'},
{"format", required_argument, nullptr, 'f'},
{nullptr}
};
std::string outputFile;
size_t segmentSize = 0;
massivedynamic::Type type = massivedynamic::Type::MEDIUM;
massivedynamic::Format format = massivedynamic::Format::CONSOLE;
bool fromStdin = true;
std::string paramData = "";
for(;;) {
int index = -1;
int result = getopt_long(argc, argv, "ho:s:t:f:i:", options, &index);
if (result == -1)
break;
const option* opt = &options[index];
UNUSED(opt);
switch(result) {
case 'o': {
if (strlen(optarg) > 0)
outputFile = optarg;
break;
}
case 's': {
segmentSize = std::atoi(optarg);
break;
}
case 't': {
std::string value = optarg;
if (value == "small")
type = massivedynamic::Type::SMALL;
else if (value == "medium")
type = massivedynamic::Type::MEDIUM;
else if (value == "large")
type = massivedynamic::Type::LARGE;
else {
printHelp();
return 1;
}
break;
}
case 'f': {
std::string value = optarg;
if (value == "cli")
format = massivedynamic::Format::CONSOLE;
else if (value == "svg")
format = massivedynamic::Format::SVG;
else if (value == "png")
format = massivedynamic::Format::PNG;
else {
printHelp();
return 1;
}
break;
}
case 'i': {
fromStdin = false;
paramData = optarg;
break;
}
case 'h':
default:
printHelp();
return 0;
}
}
std::string line;
std::stringstream data;
if (fromStdin) {
if (!isatty(fileno(stdin))) {
while (std::getline(std::cin, line)) {
if (std::cin.eof() || line.empty()) {
std::cin.clear();
break;
}
data << line;
}
}
if (isatty(fileno(stdin)) || data.str().empty()) {
std::cerr << "ERROR: no data from stdinput." << std::endl;
exit(1);
}
} else
data << paramData;
if (data.str().empty()) {
std::cerr << "ERROR: input data is empty" << std::endl;
exit(1);
}
if ((format == massivedynamic::Format::PNG || format == massivedynamic::Format::SVG) && outputFile.empty()) {
std::cerr << "ERROR: output file name (-o, --output) can not be empty" << std::endl;
return 1;
}
std::unique_ptr<massivedynamic::QR> qr = std::make_unique<massivedynamic::QR>(data.str(), outputFile, segmentSize, type, format);
return 0;
}