Preparse ConfigProto objects.

This commit is contained in:
dg
2023-05-07 19:28:29 +00:00
parent 71a7f3554e
commit db004bc787
14 changed files with 159 additions and 143 deletions

View File

@@ -48,7 +48,7 @@ AR ?= $(CCPREFIX)ar
PKG_CONFIG ?= pkg-config
WX_CONFIG ?= wx-config
PROTOC ?= protoc
CFLAGS ?= -g -Os
CFLAGS ?= -g -O3
CXXFLAGS += -std=c++17
LDFLAGS ?=
PLATFORM ?= UNIX

View File

@@ -279,7 +279,7 @@ void FlagGroup::parseFlags(int argc,
void FlagGroup::parseFlagsWithConfigFiles(int argc,
const char* argv[],
const std::map<std::string, std::string>& configFiles)
const std::map<std::string, const ConfigProto*>& configFiles)
{
parseFlags(argc,
argv,
@@ -291,16 +291,11 @@ void FlagGroup::parseFlagsWithConfigFiles(int argc,
}
ConfigProto FlagGroup::parseSingleConfigFile(const std::string& filename,
const std::map<std::string, std::string>& configFiles)
const std::map<std::string, const ConfigProto*>& configFiles)
{
const auto& it = configFiles.find(filename);
if (it != configFiles.end())
{
ConfigProto config;
if (!config.ParseFromString(it->second))
Error() << "couldn't load built-in config proto";
return config;
}
return *it->second;
else
{
std::ifstream f(filename, std::ios::out);
@@ -319,7 +314,7 @@ ConfigProto FlagGroup::parseSingleConfigFile(const std::string& filename,
}
void FlagGroup::parseConfigFile(const std::string& filename,
const std::map<std::string, std::string>& configFiles)
const std::map<std::string, const ConfigProto*>& configFiles)
{
auto newConfig = parseSingleConfigFile(filename, configFiles);

View File

@@ -31,19 +31,19 @@ public:
});
void parseFlagsWithConfigFiles(int argc,
const char* argv[],
const std::map<std::string, std::string>& configFiles);
const std::map<std::string, const ConfigProto*>& configFiles);
/* Load one config file (or internal config file), without expanding
* includes. */
static ConfigProto parseSingleConfigFile(const std::string& filename,
const std::map<std::string, std::string>& configFiles);
const std::map<std::string, const ConfigProto*>& configFiles);
/* Load a top-level config file (or internal config file), expanding
* includes. */
static void parseConfigFile(const std::string& filename,
const std::map<std::string, std::string>& configFiles);
const std::map<std::string, const ConfigProto*>& configFiles);
/* Modify the current config to engage the named option. */

View File

@@ -246,3 +246,12 @@ findAllProtoFields(google::protobuf::Message* message)
recurse(descriptor, "");
return fields;
}
ConfigProto parseConfigBytes(const std::string_view& data)
{
ConfigProto proto;
if (!proto.ParseFromArray(data.begin(), data.size()))
Error() << "invalid internal config data";
return proto;
}

View File

@@ -18,6 +18,8 @@ extern std::set<unsigned> iterate(unsigned start, unsigned count);
extern std::map<std::string, const google::protobuf::FieldDescriptor*>
findAllProtoFields(google::protobuf::Message* message);
extern ConfigProto parseConfigBytes(const std::string_view& bytes);
extern ConfigProto config;
#endif

View File

@@ -3,15 +3,11 @@
#include "lib/flags.h"
#include <fmt/format.h>
extern const std::map<std::string, std::string> formats;
extern const std::map<std::string, const ConfigProto*> formats;
static ConfigProto findConfig(std::string name)
static const ConfigProto& findConfig(std::string name)
{
const auto data = formats.at(name);
ConfigProto config;
if (!config.ParseFromString(data))
Error() << "bad config name: " + name;
return config;
return *formats.at(name);
}
int main(int argc, const char* argv[])

View File

@@ -1,18 +1,19 @@
#!/bin/sh
echo "#include <string>"
echo "#include <map>"
echo "class ConfigProto;"
word=$1
shift
for a in "$@"; do
echo "extern std::string ${word}_${a}_pb();"
echo "extern const ConfigProto ${word}_${a}_pb;"
done
echo "extern const std::map<std::string, std::string> ${word};"
echo "const std::map<std::string, std::string> ${word} = {"
echo "extern const std::map<std::string, const ConfigProto*> ${word};"
echo "const std::map<std::string, const ConfigProto*> ${word} = {"
for a in "$@"; do
echo " { \"${a}\", ${word}_${a}_pb() },"
echo " { \"${a}\", &${word}_${a}_pb },"
done
echo "};"

View File

@@ -12,100 +12,100 @@
static uint32_t readu8(std::string::iterator& it, std::string::iterator end)
{
int len;
int len;
uint32_t c = *it++;
if (c < 0x80)
{
/* Do nothing! */
len = 0;
len = 0;
}
else if (c < 0xc0)
{
/* Invalid character */
c = -1;
len = 0;
len = 0;
}
else if (c < 0xe0)
{
/* One trailing byte */
c &= 0x1f;
len = 1;
len = 1;
}
else if (c < 0xf0)
{
/* Two trailing bytes */
c &= 0x0f;
len = 2;
len = 2;
}
else if (c < 0xf8)
{
/* Three trailing bytes */
c &= 0x07;
len = 3;
len = 3;
}
else if (c < 0xfc)
{
/* Four trailing bytes */
c &= 0x03;
len = 4;
len = 4;
}
else
{
/* Five trailing bytes */
c &= 0x01;
len = 5;
len = 5;
}
while (len)
{
if (it == end)
break;
while (len)
{
if (it == end)
break;
uint8_t d = *it++;
c <<= 6;
c += d & 0x3f;
}
uint8_t d = *it++;
c <<= 6;
c += d & 0x3f;
}
return c;
}
int main(int argc, const char* argv[])
{
PROTO message;
PROTO message;
std::ifstream input(argv[1]);
if (!input)
{
perror("couldn't open input file");
exit(1);
}
std::ifstream input(argv[1]);
if (!input)
{
perror("couldn't open input file");
exit(1);
}
std::stringstream ss;
std::string s;
while (std::getline(input, s, '\n'))
{
if (s == "<<<")
{
while (std::getline(input, s, '\n'))
{
if (s == ">>>")
break;
std::stringstream ss;
std::string s;
while (std::getline(input, s, '\n'))
{
if (s == "<<<")
{
while (std::getline(input, s, '\n'))
{
if (s == ">>>")
break;
ss << '"';
auto it = s.begin();
for (;;)
{
uint32_t u = readu8(it, s.end());
if (!u)
break;
ss << '"';
auto it = s.begin();
for (;;)
{
uint32_t u = readu8(it, s.end());
if (!u)
break;
ss << fmt::format("\\u{:04x}", u);
}
ss << "\\n\"\n";
}
}
else
ss << s << '\n';
}
ss << fmt::format("\\u{:04x}", u);
}
ss << "\\n\"\n";
}
}
else
ss << s << '\n';
}
if (!google::protobuf::TextFormat::ParseFromString(ss.str(), &message))
{
@@ -113,34 +113,39 @@ int main(int argc, const char* argv[])
exit(1);
}
std::ofstream output(argv[2]);
if (!output)
{
perror("couldn't open output file");
exit(1);
}
std::ofstream output(argv[2]);
if (!output)
{
perror("couldn't open output file");
exit(1);
}
auto data = message.SerializeAsString();
output << "#include <string>\n"
<< "static const unsigned char data[] = {\n";
output << "#include \"lib/proto.h\"\n"
<< "#include <string_view>\n"
<< "static const uint8_t rawData[] = {";
int count = 0;
for (char c : data)
{
int count = 0;
for (char c : data)
{
if (count == 0)
output << "\n\t";
else
output << ' ';
output << fmt::format("0x{:02x},", (unsigned char)c);
count = (count+1) & 7;
}
count = (count + 1) & 7;
}
output << "};\n"
<< fmt::format("extern std::string {}();\n", argv[3])
<< fmt::format("std::string {}()\n", argv[3])
<< "{ return std::string((const char*)data, sizeof(data)); }\n";
output << "\n};\n";
output << "extern const std::string_view " << argv[3] << "_data;\n";
output << "const std::string_view " << argv[3]
<< "_data = std::string_view((const char*)rawData, " << data.size()
<< ");\n";
output << "extern const ConfigProto " << argv[3] << ";\n";
output << "const ConfigProto " << argv[3] << " = parseConfigBytes("
<< argv[3] << "_data);\n";
return 0;
}

View File

@@ -36,6 +36,7 @@ struct Command
static command_cb mainAnalyse;
static command_cb mainTest;
// clang-format off
static std::vector<Command> commands =
{
{ "inspect", mainInspect, "Low-level analysis and inspection of a disk." },
@@ -70,10 +71,13 @@ static std::vector<Command> testables =
{ "bandwidth", mainTestBandwidth, "Measures your USB bandwidth.", },
{ "voltages", mainTestVoltages, "Measures the FDD bus voltages.", },
};
// clang-format on
static void extendedHelp(std::vector<Command>& subcommands, const std::string& command)
static void extendedHelp(
std::vector<Command>& subcommands, const std::string& command)
{
std::cout << "fluxengine: syntax: fluxengine " << command << " <format> [<flags>...]\n"
std::cout << "fluxengine: syntax: fluxengine " << command
<< " <format> [<flags>...]\n"
"These subcommands are supported:\n";
for (Command& c : subcommands)
@@ -82,8 +86,10 @@ static void extendedHelp(std::vector<Command>& subcommands, const std::string& c
exit(0);
}
static int mainExtended(std::vector<Command>& subcommands, const std::string& command,
int argc, const char* argv[])
static int mainExtended(std::vector<Command>& subcommands,
const std::string& command,
int argc,
const char* argv[])
{
if (argc == 1)
extendedHelp(subcommands, command);
@@ -95,7 +101,7 @@ static int mainExtended(std::vector<Command>& subcommands, const std::string& co
for (Command& c : subcommands)
{
if (format == c.name)
return c.main(argc-1, argv+1);
return c.main(argc - 1, argv + 1);
}
std::cerr << "fluxengine: unrecognised format (try --help)\n";
@@ -103,10 +109,14 @@ static int mainExtended(std::vector<Command>& subcommands, const std::string& co
}
static int mainAnalyse(int argc, const char* argv[])
{ return mainExtended(analysables, "analyse", argc, argv); }
{
return mainExtended(analysables, "analyse", argc, argv);
}
static int mainTest(int argc, const char* argv[])
{ return mainExtended(testables, "test", argc, argv); }
{
return mainExtended(testables, "test", argc, argv);
}
static void globalHelp()
{
@@ -119,34 +129,32 @@ static void globalHelp()
exit(0);
}
void showProfiles(const std::string& command, const std::map<std::string, std::string>& profiles)
void showProfiles(const std::string& command,
const std::map<std::string, const ConfigProto*>& profiles)
{
std::cout << "syntax: fluxengine " << command << " <profile> [<extensions...>] [<options>...]\n"
"Use --help for option help.\n"
"Available profiles include:\n";
std::cout << "syntax: fluxengine " << command
<< " <profile> [<extensions...>] [<options>...]\n"
"Use --help for option help.\n"
"Available profiles include:\n";
for (const auto& it : profiles)
{
ConfigProto config;
if (!config.ParseFromString(it.second))
Error() << "couldn't load config proto";
if (!config.is_extension())
std::cout << fmt::format(" {}: {}\n", it.first, config.comment());
}
for (const auto& it : profiles)
{
const auto& config = *it.second;
if (!config.is_extension())
std::cout << fmt::format(" {}: {}\n", it.first, config.comment());
}
std::cout << "Available profile options include:\n";
std::cout << "Available profile options include:\n";
for (const auto& it : profiles)
{
ConfigProto config;
if (!config.ParseFromString(it.second))
Error() << "couldn't load config proto";
if (config.is_extension() && (it.first[0] != '_'))
std::cout << fmt::format(" {}: {}\n", it.first, config.comment());
}
for (const auto& it : profiles)
{
const auto& config = *it.second;
if (config.is_extension() && (it.first[0] != '_'))
std::cout << fmt::format(" {}: {}\n", it.first, config.comment());
}
std::cout << "Profiles and extensions may also be textpb files .\n";
exit(1);
std::cout << "Profiles and extensions may also be textpb files .\n";
exit(1);
}
int main(int argc, const char* argv[])
@@ -161,17 +169,17 @@ int main(int argc, const char* argv[])
for (Command& c : commands)
{
if (command == c.name)
{
try
{
return c.main(argc-1, argv+1);
}
catch (const ErrorException& e)
{
e.print();
exit(1);
}
}
{
try
{
return c.main(argc - 1, argv + 1);
}
catch (const ErrorException& e)
{
e.print();
exit(1);
}
}
}
std::cerr << "fluxengine: unrecognised command (try --help)\n";

View File

@@ -1,8 +1,9 @@
#ifndef FLUXENGINE_H
#define FLUXENGINE_H
extern void showProfiles(const std::string& command, const std::map<std::string, std::string>& profiles);
extern void showProfiles(const std::string& command,
const std::map<std::string, const ConfigProto*>& profiles);
extern const std::map<std::string, std::string> formats;
extern const std::map<std::string, const ConfigProto*> formats;
#endif

View File

@@ -67,6 +67,7 @@ $(OBJDIR)/scripts/mkdoc.o: scripts/mkdoc.cc
$(call use-library, $(OBJDIR)/mkdoc.exe, $(OBJDIR)/scripts/mkdoc.o, PROTO)
$(call use-library, $(OBJDIR)/mkdoc.exe, $(OBJDIR)/scripts/mkdoc.o, LIBFORMATS)
$(call use-library, $(OBJDIR)/mkdoc.exe, $(OBJDIR)/scripts/mkdoc.o, LIBFLUXENGINE)
docs: $(patsubst %, doc/disk-%.md, $(FORMATS))

View File

@@ -20,7 +20,7 @@
#include ".obj/extras/fluxfile.h"
#include ".obj/extras/imagefile.h"
extern const std::map<std::string, std::string> formats;
extern const std::map<std::string, const ConfigProto*> formats;
#define CONFIG_SELECTEDSOURCE "SelectedSource"
#define CONFIG_DEVICE "Device"
@@ -76,8 +76,7 @@ public:
for (const auto& it : formats)
{
auto config = std::make_unique<ConfigProto>();
if (!config->ParseFromString(it.second))
continue;
*config = *it.second;
if (config->is_extension())
continue;

View File

@@ -4,7 +4,7 @@
#include "lib/bytes.h"
#include <fmt/format.h>
extern const std::map<std::string, std::string> formats;
extern const std::map<std::string, const ConfigProto*> formats;
bool failed = false;
@@ -41,13 +41,12 @@ struct fmt::formatter<std::vector<std::string>>
}
};
static ConfigProto findConfig(std::string name)
static const ConfigProto& findConfig(std::string name)
{
const auto data = formats.at(name);
ConfigProto config;
if (!config.ParseFromString(data))
const auto it = formats.find(name);
if (it == formats.end())
error("{}: couldn't load", name);
return config;
return *it->second;
}
static std::vector<std::vector<std::string>> generateCombinations(

View File

@@ -81,10 +81,10 @@ static void test_config(void)
static void test_load(void)
{
extern std::string testproto_pb();
extern std::string_view testproto_pb_data;
TestProto proto;
bool r = proto.ParseFromString(testproto_pb());
bool r = proto.ParseFromArray(testproto_pb_data.begin(), testproto_pb_data.size());
std::string s;
google::protobuf::TextFormat::PrintToString(proto, &s);