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.
106 lines
3.3 KiB
106 lines
3.3 KiB
/* |
|
* Copyright 2026 Axel Waggershauser |
|
*/ |
|
// SPDX-License-Identifier: Apache-2.0 |
|
|
|
#include "BarcodeFormat.h" |
|
|
|
#include <version> |
|
#ifdef __cpp_lib_format |
|
|
|
#include "StdPrint.h" |
|
|
|
#include <cctype> |
|
#include <cstring> |
|
#include <format> |
|
#include <functional> |
|
#include <string> |
|
|
|
static void PrintUsage(const char* exePath) |
|
{ |
|
std::print("ZXingBarcodeFormat - A command line tool to generate wrapper source code for the BarcodeFormat enum\n\n"); |
|
std::println("Usage: {} <Android|C#|Go|K/N|Rust|Swift>", exePath); |
|
} |
|
|
|
static void PrintBFs( |
|
std::format_string<std::string, int> fmt, |
|
std::function<std::string(const char*)> name = [](const char* name) { return std::string(name); }) |
|
{ |
|
std::println(fmt, name("Invalid"), 0xffff); |
|
#define X(NAME, SYM, VAR, FLAGS, ZINT, ENABLED, HRI) std::println(fmt, name(#NAME), ZX_BCF_ID(SYM, VAR)); |
|
ZX_BCF_LIST(X) |
|
#undef X |
|
} |
|
|
|
int main(int argc, char* argv[]) |
|
{ |
|
auto is = [&, i=1](const char* str) { return strncmp(argv[i], str, strlen(argv[i])) == 0; }; |
|
|
|
if (argc != 2) { |
|
PrintUsage(argv[0]); |
|
return -1; |
|
} else if (is("Go")) { |
|
std::println("package zxingcpp\n"); |
|
std::println("const ("); |
|
PrintBFs(" BarcodeFormat{:14} BarcodeFormat = 0x{:04X}"); |
|
std::println(")"); |
|
} else if (is("C#")) { |
|
PrintBFs(" public static readonly BarcodeFormat {:15} = new BarcodeFormat(0x{:04X});"); |
|
} else if (is("K/N")) { |
|
PrintBFs(" {0:15}(ZXing_BarcodeFormat.ZXing_BarcodeFormat_{0}),"); |
|
} else if (is("Rust")) { |
|
PrintBFs("pub const ZXing_BarcodeFormat_{}: ZXing_BarcodeFormat = 0x{:04X};"); |
|
} else if (is("Swift")) { |
|
auto swiftName = [](const char* name) { |
|
std::string sv(name); |
|
std::string ret = (char)std::tolower(sv[0]) + sv.substr(1); |
|
// Convert to camelCase, but keep uppercase letters if they are followed by a lowercase letter |
|
// (e.g. QRCode -> qrCode). This is a bit hacky, but it works for the current set of names and avoids the |
|
// need for a manual mapping. This ensures that the generated Swift code follows typical naming patterns. |
|
for (int i = 2; i < ret.size() && (std::isupper(ret[i]) || std::isdigit(ret[i])); ++i) |
|
ret[i - 1] = std::tolower(ret[i - 1]); |
|
ret.back() = std::tolower(ret.back()); |
|
return ret == "eanupc" ? "eanUPC" : ret == "upca" ? "upcA" : ret == "upce" ? "upcE" : ret; |
|
}; |
|
PrintBFs(" public static let {:15} = BarcodeFormat(rawValue: 0x{:04X})", swiftName); |
|
} else if (is("Android")) { |
|
auto androidName = [](const char* name) { |
|
std::string sv(name); |
|
std::string ret = std::string(1, (char)std::toupper(sv[0])); |
|
|
|
for (size_t i = 1; i < sv.size(); ++i) { |
|
const int c = sv[i]; |
|
const int prev = sv[i - 1]; |
|
const int next = i + 1 < sv.size() ? sv[i + 1] : 0; |
|
if ((std::isdigit(c) != std::isdigit(prev)) || (std::isupper(c) && std::islower(prev)) |
|
|| (std::isupper(c) && std::isupper(prev) && next != 0 && std::islower(next))) |
|
ret.push_back('_'); |
|
ret.push_back(static_cast<char>(std::toupper(c))); |
|
} |
|
|
|
return ret == "EANUPC" ? "EAN_UPC" |
|
: ret == "UPCA" ? "UPC_A" |
|
: ret == "UPCE" ? "UPC_E" |
|
: ret == "ALL_GS_1" ? "ALL_GS1" |
|
: ret; |
|
}; |
|
PrintBFs("\t\t{:20}(0x{:04X}),", androidName); |
|
} else { |
|
PrintUsage(argv[0]); |
|
return -1; |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
#else |
|
|
|
#include <cstdio> |
|
|
|
int main() |
|
{ |
|
printf("This tool requires C++20 support with std::format. Please use a compatible compiler.\n"); |
|
return -1; |
|
} |
|
|
|
#endif
|
|
|