First milestone towards flags rewrite --- it builds and the tests pass, but

nothing actually works.
This commit is contained in:
David Given
2019-07-02 23:06:40 +02:00
parent bba2f856a5
commit a1c207cb8f
32 changed files with 247 additions and 79 deletions

View File

@@ -58,15 +58,21 @@ public:
DataSpecFlag(const std::vector<std::string>& names, const std::string helptext,
const std::string& defaultValue):
Flag(names, helptext),
value(defaultValue)
_value(defaultValue)
{}
bool hasArgument() const { return true; }
const std::string defaultValueAsString() const { return value; }
void set(const std::string& value) { this->value.set(value); }
const DataSpec& get() const
{ checkInitialised(); return _value; }
public:
DataSpec value;
operator const DataSpec& () const
{ return get(); }
bool hasArgument() const { return true; }
const std::string defaultValueAsString() const { return _value; }
void set(const std::string& value) { _value.set(value); }
private:
DataSpec _value;
};
#endif

View File

@@ -8,7 +8,9 @@
#include <math.h>
#include <strings.h>
static DoubleFlag pulseDebounceThreshold(
FlagGroup fluxmapReaderFlags;
DoubleFlag pulseDebounceThreshold(
{ "--pulse-debounce-threshold" },
"Ignore pulses with intervals short than this, in fractions of a clock.",
0.30);

View File

@@ -3,6 +3,9 @@
#include "fluxmap.h"
#include "protocol.h"
#include "flags.h"
extern FlagGroup fluxmapReaderFlags;
class FluxMatcher;

View File

@@ -1,25 +1,68 @@
#include "globals.h"
#include "flags.h"
static FlagGroup* currentFlagGroup;
static std::vector<Flag*> all_flags;
static std::map<const std::string, Flag*> flags_by_name;
Flag::Flag(const std::vector<std::string>& names, const std::string helptext):
_names(names),
_helptext(helptext)
{
for (auto& name : names)
{
if (flags_by_name.find(name) != flags_by_name.end())
Error() << "two flags use the name '" << name << "'";
flags_by_name[name] = this;
}
static void doHelp();
all_flags.push_back(this);
static FlagGroup helpGroup;
static ActionFlag helpFlag = ActionFlag(
{ "--help", "-h" },
"Shows the help.",
doHelp);
FlagGroup::FlagGroup(const std::initializer_list<FlagGroup*> groups):
_groups(groups.begin(), groups.end())
{
currentFlagGroup = this;
}
void Flag::parseFlags(int argc, const char* argv[])
FlagGroup::FlagGroup()
{
currentFlagGroup = this;
}
void FlagGroup::addFlag(Flag* flag)
{
_flags.push_back(flag);
}
void FlagGroup::parseFlags(int argc, const char* argv[])
{
if (_initialised)
throw std::runtime_error("called parseFlags() twice");
/* Recursively accumulate a list of all flags. */
all_flags.clear();
flags_by_name.clear();
std::function<void(FlagGroup*)> recurse;
recurse = [&](FlagGroup* group)
{
if (group->_initialised)
return;
for (FlagGroup* subgroup : group->_groups)
recurse(subgroup);
for (Flag* flag : group->_flags)
{
const auto& name = flag->name();
if (flags_by_name.find(name) != flags_by_name.end())
Error() << "two flags use the name '" << name << "'";
flags_by_name[name] = flag;
all_flags.push_back(flag);
}
group->_initialised = true;
};
recurse(this);
/* Now actually parse them. */
int index = 1;
while (index < argc)
{
@@ -76,15 +119,28 @@ void Flag::parseFlags(int argc, const char* argv[])
if (usesthat && flag->second->hasArgument())
index++;
}
}
void FlagGroup::checkInitialised() const
{
if (!_initialised)
throw std::runtime_error("Attempt to access uninitialised flag");
}
Flag::Flag(const std::vector<std::string>& names, const std::string helptext):
_group(*currentFlagGroup),
_names(names),
_helptext(helptext)
{
_group.addFlag(this);
}
void BoolFlag::set(const std::string& value)
{
if ((value == "true") || (value == "y"))
this->value = true;
_value = true;
else if ((value == "false") || (value == "n"))
this->value = false;
_value = false;
else
Error() << "can't parse '" << value << "'; try 'true' or 'false'";
}
@@ -110,8 +166,3 @@ static void doHelp()
}
exit(0);
}
static ActionFlag helpFlag = ActionFlag(
{ "--help", "-h" },
"Shows the help.",
doHelp);

View File

@@ -2,15 +2,36 @@
#define FLAGS_H
class DataSpec;
class Flag;
class FlagGroup
{
private:
FlagGroup(const FlagGroup& group);
public:
FlagGroup(const std::initializer_list<FlagGroup*> groups);
FlagGroup();
public:
void parseFlags(int argc, const char* argv[]);
void addFlag(Flag* flag);
void checkInitialised() const;
private:
bool _initialised = false;
const std::vector<FlagGroup*> _groups;
std::vector<Flag*> _flags;
};
class Flag
{
public:
static void parseFlags(int argc, const char* argv[]);
Flag(const std::vector<std::string>& names, const std::string helptext);
virtual ~Flag() {};
void checkInitialised() const
{ _group.checkInitialised(); }
const std::string& name() const { return _names[0]; }
const std::vector<std::string> names() const { return _names; }
const std::string& helptext() const { return _helptext; }
@@ -20,6 +41,7 @@ public:
virtual void set(const std::string& value) = 0;
private:
FlagGroup& _group;
const std::vector<std::string> _names;
const std::string _helptext;
};
@@ -48,7 +70,8 @@ public:
Flag(names, helptext)
{}
operator bool() const { return _value; }
operator bool() const
{ checkInitialised(); return _value; }
bool hasArgument() const { return false; }
const std::string defaultValueAsString() const { return "false"; }
@@ -65,16 +88,26 @@ public:
ValueFlag(const std::vector<std::string>& names, const std::string helptext,
const T defaultValue):
Flag(names, helptext),
defaultValue(defaultValue),
value(defaultValue)
_defaultValue(defaultValue),
_value(defaultValue)
{}
operator T() const { return value; }
const T& get() const
{ checkInitialised(); return _value; }
operator const T& () const
{ return get(); }
void setDefaultValue(T value)
{
_value = _defaultValue = value;
}
bool hasArgument() const { return true; }
T defaultValue;
T value;
protected:
T _defaultValue;
T _value;
};
class StringFlag : public ValueFlag<std::string>
@@ -85,8 +118,8 @@ public:
ValueFlag(names, helptext, defaultValue)
{}
const std::string defaultValueAsString() const { return defaultValue; }
void set(const std::string& value) { this->value = value; }
const std::string defaultValueAsString() const { return _defaultValue; }
void set(const std::string& value) { _value = value; }
};
class IntFlag : public ValueFlag<int>
@@ -97,8 +130,8 @@ public:
ValueFlag(names, helptext, defaultValue)
{}
const std::string defaultValueAsString() const { return std::to_string(defaultValue); }
void set(const std::string& value) { this->value = std::stoi(value); }
const std::string defaultValueAsString() const { return std::to_string(_defaultValue); }
void set(const std::string& value) { _value = std::stoi(value); }
};
class DoubleFlag : public ValueFlag<double>
@@ -109,8 +142,8 @@ public:
ValueFlag(names, helptext, defaultValue)
{}
const std::string defaultValueAsString() const { return std::to_string(defaultValue); }
void set(const std::string& value) { this->value = std::stod(value); }
const std::string defaultValueAsString() const { return std::to_string(_defaultValue); }
void set(const std::string& value) { _value = std::stod(value); }
};
class BoolFlag : public ValueFlag<double>
@@ -121,7 +154,7 @@ public:
ValueFlag(names, helptext, defaultValue)
{}
const std::string defaultValueAsString() const { return defaultValue ? "true" : "false"; }
const std::string defaultValueAsString() const { return _defaultValue ? "true" : "false"; }
void set(const std::string& value);
};

View File

@@ -4,6 +4,8 @@
#include "usb.h"
#include "fluxsource.h"
FlagGroup hardwareFluxSourceFlags;
static IntFlag revolutions(
{ "--revolutions" },
"read this many revolutions of the disk",
@@ -56,7 +58,7 @@ private:
void setHardwareFluxSourceRevolutions(int revolutions)
{
::revolutions.value = ::revolutions.defaultValue = revolutions;
::revolutions.setDefaultValue(revolutions);
}
std::unique_ptr<FluxSource> FluxSource::createHardwareFluxSource(unsigned drive)

View File

@@ -16,6 +16,8 @@
#include "track.h"
#include "fmt/format.h"
FlagGroup readerFlags;
static DataSpecFlag source(
{ "--source", "-s" },
"source for data",
@@ -69,16 +71,16 @@ void Track::readFluxmap()
std::vector<std::unique_ptr<Track>> readTracks()
{
const DataSpec& dataSpec = source.value;
const DataSpec& dataSpec = source;
std::cout << "Reading from: " << dataSpec << std::endl;
setHardwareFluxSourceDensity(highDensityFlag);
if (!destination.value.empty())
if (!destination.get().empty())
{
outdb = sqlOpen(destination, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
std::cout << "Writing a copy of the flux to " << destination.value << std::endl;
std::cout << "Writing a copy of the flux to " << destination.get() << std::endl;
sqlPrepareFlux(outdb);
sqlStmt(outdb, "BEGIN;");
sqlWriteIntProperty(outdb, "version", FLUX_VERSION_CURRENT);

View File

@@ -10,6 +10,8 @@
#include "fluxsink.h"
#include "fmt/format.h"
FlagGroup writerFlags;
static DataSpecFlag dest(
{ "--dest", "-d" },
"destination for data",
@@ -29,7 +31,7 @@ void setWriterDefaultDest(const std::string& dest)
void writeTracks(
const std::function<std::unique_ptr<Fluxmap>(int track, int side)> producer)
{
const auto& spec = dest.value;
const DataSpec& spec = dest;
std::cout << "Writing to: " << spec << std::endl;

View File

@@ -3,10 +3,12 @@
#include "fluxmap.h"
#include "writer.h"
FlagGroup flags;
int main(int argc, const char* argv[])
{
setWriterDefaultDest(":t=0-81:s=0-1");
Flag::parseFlags(argc, argv);
flags.parseFlags(argc, argv);
writeTracks(
[](int physicalTrack, int physicalSide) -> std::unique_ptr<Fluxmap>

View File

@@ -12,6 +12,8 @@
#include "track.h"
#include <fmt/format.h>
FlagGroup flags;
static SettableFlag dumpFluxFlag(
{ "--dump-flux", "-F" },
"Dump raw magnetic disk flux.");
@@ -51,7 +53,7 @@ static DoubleFlag signalLevelFactor(
void setDecoderManualClockRate(double clockrate_us)
{
manualClockRate.value = clockrate_us;
manualClockRate.setDefaultValue(clockrate_us);
}
static const std::string BLOCK_ELEMENTS[] =
@@ -175,7 +177,7 @@ static nanoseconds_t guessClock(const Fluxmap& fluxmap)
int main(int argc, const char* argv[])
{
Flag::parseFlags(argc, argv);
flags.parseFlags(argc, argv);
const auto& tracks = readTracks();
if (tracks.size() != 1)

View File

@@ -10,6 +10,8 @@
#include "ibm.h"
#include <fmt/format.h>
FlagGroup flags;
static StringFlag outputFilename(
{ "--output", "-o" },
"The output image file to write to.",
@@ -23,7 +25,7 @@ static IntFlag sectorIdBase(
int main(int argc, const char* argv[])
{
setReaderDefaultSource(":t=0-79:s=0-1");
Flag::parseFlags(argc, argv);
flags.parseFlags(argc, argv);
IbmDecoder decoder(sectorIdBase);
readDiskCommand(decoder, outputFilename);

View File

@@ -10,6 +10,8 @@
#include "aeslanier.h"
#include <fmt/format.h>
FlagGroup flags;
static StringFlag outputFilename(
{ "--output", "-o" },
"The output image file to write to.",
@@ -19,7 +21,7 @@ int main(int argc, const char* argv[])
{
setReaderDefaultSource(":t=0-79:s=0");
setReaderRevolutions(2);
Flag::parseFlags(argc, argv);
flags.parseFlags(argc, argv);
AesLanierDecoder decoder;
readDiskCommand(decoder, outputFilename);

View File

@@ -11,6 +11,8 @@
#include <fmt/format.h>
#include <fstream>
FlagGroup flags;
static StringFlag outputFilename(
{ "--output", "-o" },
"The output image file to write to.",
@@ -20,7 +22,7 @@ int main(int argc, const char* argv[])
{
setReaderDefaultSource(":t=0-79:s=0-1");
setReaderRevolutions(2);
Flag::parseFlags(argc, argv);
flags.parseFlags(argc, argv);
AmigaDecoder decoder;
readDiskCommand(decoder, outputFilename);

View File

@@ -10,6 +10,8 @@
#include "ibm.h"
#include <fmt/format.h>
FlagGroup flags;
static StringFlag outputFilename(
{ "--output", "-o" },
"The output image file to write to.",
@@ -24,7 +26,7 @@ int main(int argc, const char* argv[])
{
setReaderDefaultSource(":t=0-79:s=0");
setReaderRevolutions(2);
Flag::parseFlags(argc, argv);
flags.parseFlags(argc, argv);
IbmDecoder decoder(sectorIdBase);
readDiskCommand(decoder, outputFilename);

View File

@@ -11,6 +11,8 @@
#include <fmt/format.h>
#include <fstream>
FlagGroup flags;
static StringFlag outputFilename(
{ "--output", "-o" },
"The output image file to write to.",
@@ -20,7 +22,7 @@ int main(int argc, const char* argv[])
{
setReaderDefaultSource(":t=0-79:s=0");
setReaderRevolutions(2);
Flag::parseFlags(argc, argv);
flags.parseFlags(argc, argv);
Apple2Decoder decoder;
readDiskCommand(decoder, outputFilename);

View File

@@ -11,6 +11,8 @@
#include <fmt/format.h>
#include <fstream>
FlagGroup flags;
static StringFlag outputFilename(
{ "--output", "-o" },
"The output image file to write to.",
@@ -20,7 +22,7 @@ int main(int argc, const char* argv[])
{
setReaderDefaultSource(":t=0-81:s=0");
setReaderRevolutions(2);
Flag::parseFlags(argc, argv);
flags.parseFlags(argc, argv);
BrotherDecoder decoder;
readDiskCommand(decoder, outputFilename);

View File

@@ -11,6 +11,8 @@
#include <fmt/format.h>
#include <fstream>
FlagGroup flags;
static StringFlag outputFilename(
{ "--output", "-o" },
"The output image file to write to.",
@@ -20,7 +22,7 @@ int main(int argc, const char* argv[])
{
setReaderDefaultSource(":t=0-79x2:s=0");
setReaderRevolutions(2);
Flag::parseFlags(argc, argv);
flags.parseFlags(argc, argv);
Commodore64Decoder decoder;
readDiskCommand(decoder, outputFilename);

View File

@@ -10,6 +10,8 @@
#include "ibm.h"
#include <fmt/format.h>
FlagGroup flags;
static StringFlag outputFilename(
{ "--output", "-o" },
"The output image file to write to.",
@@ -24,7 +26,7 @@ int main(int argc, const char* argv[])
{
setReaderDefaultSource(":t=0-79:s=0");
setReaderRevolutions(2);
Flag::parseFlags(argc, argv);
flags.parseFlags(argc, argv);
IbmDecoder decoder(sectorIdBase);
readDiskCommand(decoder, outputFilename);

View File

@@ -11,6 +11,8 @@
#include <fmt/format.h>
#include <fstream>
FlagGroup flags;
static StringFlag outputFilename(
{ "--output", "-o" },
"The output image file to write to.",
@@ -20,7 +22,7 @@ int main(int argc, const char* argv[])
{
setReaderDefaultSource(":t=0-79:s=0");
setReaderRevolutions(2);
Flag::parseFlags(argc, argv);
flags.parseFlags(argc, argv);
DurangoF85Decoder decoder;
readDiskCommand(decoder, outputFilename);

View File

@@ -10,6 +10,8 @@
#include "fb100.h"
#include <fmt/format.h>
FlagGroup flags;
static StringFlag outputFilename(
{ "--output", "-o" },
"The output image file to write to.",
@@ -19,7 +21,7 @@ int main(int argc, const char* argv[])
{
setReaderDefaultSource(":t=0-79x2:s=0");
setReaderRevolutions(2);
Flag::parseFlags(argc, argv);
flags.parseFlags(argc, argv);
Fb100Decoder decoder;
readDiskCommand(decoder, outputFilename);

View File

@@ -10,6 +10,8 @@
#include "ibm.h"
#include <fmt/format.h>
FlagGroup flags;
static StringFlag outputFilename(
{ "--output", "-o" },
"The output image file to write to.",
@@ -23,7 +25,7 @@ static IntFlag sectorIdBase(
int main(int argc, const char* argv[])
{
setReaderDefaultSource(":t=0-79:s=0-1");
Flag::parseFlags(argc, argv);
flags.parseFlags(argc, argv);
IbmDecoder decoder(sectorIdBase);
readDiskCommand(decoder, outputFilename);

View File

@@ -11,6 +11,8 @@
#include <fmt/format.h>
#include <fstream>
FlagGroup flags;
static StringFlag outputFilename(
{ "--output", "-o" },
"The output image file to write to.",
@@ -20,7 +22,7 @@ int main(int argc, const char* argv[])
{
setReaderDefaultSource(":t=0-79:s=0-1");
setReaderRevolutions(2);
Flag::parseFlags(argc, argv);
flags.parseFlags(argc, argv);
MacintoshDecoder decoder;
readDiskCommand(decoder, outputFilename);

View File

@@ -11,6 +11,8 @@
#include <fmt/format.h>
#include <fstream>
FlagGroup flags;
static StringFlag outputFilename(
{ "--output", "-o" },
"The output image file to write to.",
@@ -20,7 +22,7 @@ int main(int argc, const char* argv[])
{
setReaderDefaultSource(":t=0-79:s=0");
setReaderRevolutions(2);
Flag::parseFlags(argc, argv);
flags.parseFlags(argc, argv);
Victor9kDecoder decoder;
readDiskCommand(decoder, outputFilename);

View File

@@ -10,6 +10,8 @@
#include "zilogmcz.h"
#include <fmt/format.h>
FlagGroup flags;
static StringFlag outputFilename(
{ "--output", "-o" },
"The output image file to write to.",
@@ -19,7 +21,7 @@ int main(int argc, const char* argv[])
{
setReaderDefaultSource(":t=0-76:s=0");
setReaderRevolutions(2);
Flag::parseFlags(argc, argv);
flags.parseFlags(argc, argv);
ZilogMczDecoder decoder;
readDiskCommand(decoder, outputFilename);

View File

@@ -3,6 +3,8 @@
#include "usb.h"
#include "dataspec.h"
FlagGroup flags;
static DataSpecFlag source(
{ "--source", "-s" },
"source for data",
@@ -10,9 +12,9 @@ static DataSpecFlag source(
int main(int argc, const char* argv[])
{
Flag::parseFlags(argc, argv);
flags.parseFlags(argc, argv);
usbSetDrive(source.value.drive, false);
usbSetDrive(source.get().drive, false);
nanoseconds_t period = usbGetRotationalPeriod();
std::cout << "Rotational period is " << period/1000 << " ms (" << 60e6/period << " rpm)" << std::endl;

View File

@@ -2,6 +2,8 @@
#include "flags.h"
#include "usb.h"
FlagGroup flags;
static IntFlag drive(
{ "--drive", "-d" },
"drive to use",
@@ -14,7 +16,7 @@ static IntFlag track(
int main(int argc, const char* argv[])
{
Flag::parseFlags(argc, argv);
flags.parseFlags(argc, argv);
usbSetDrive(drive, false);
usbSeek(track);

View File

@@ -2,9 +2,11 @@
#include "flags.h"
#include "usb.h"
FlagGroup flags;
int main(int argc, const char* argv[])
{
Flag::parseFlags(argc, argv);
flags.parseFlags(argc, argv);
usbTestBulkTransport();
return 0;
}

View File

@@ -11,6 +11,8 @@
#include <fstream>
#include <ctype.h>
FlagGroup flags;
static StringFlag inputFilename(
{ "--input", "-i" },
"The input image file to read from.",
@@ -52,7 +54,7 @@ static int charToInt(char c)
int main(int argc, const char* argv[])
{
setWriterDefaultDest(":d=0:t=0-77:s=0");
Flag::parseFlags(argc, argv);
flags.parseFlags(argc, argv);
SectorSet allSectors;
Geometry geometry = {78, 1, 12, 256};

View File

@@ -10,11 +10,13 @@
#include <fstream>
#include <ctype.h>
FlagGroup flags;
int main(int argc, const char* argv[])
{
setReaderDefaultSource(":t=0-81:h=0-1");
setWriterDefaultDest(":t=0-81:s=0-1");
Flag::parseFlags(argc, argv);
flags.parseFlags(argc, argv);
auto tracks = readTracks();
for (auto& track : tracks)

View File

@@ -8,6 +8,8 @@
#include <fstream>
#include <ctype.h>
FlagGroup flags;
static DoubleFlag interval(
{ "--interval" },
"Interval between pulses (microseconds).",
@@ -21,7 +23,7 @@ static DoubleFlag sequenceLength(
int main(int argc, const char* argv[])
{
setWriterDefaultDest(":t=0-81:s=0-1");
Flag::parseFlags(argc, argv);
flags.parseFlags(argc, argv);
unsigned ticksPerInterval = (unsigned) (interval * TICKS_PER_US);

View File

@@ -2,22 +2,40 @@
#include "flags.h"
#include <assert.h>
static IntFlag intFlag(
{ "--intFlag" },
"a global integer flag",
1);
static void testDefaultIntValue()
{
intFlag.value = intFlag.defaultValue = 2;
FlagGroup flags;
IntFlag intFlag(
{ "--intFlag" },
"a global integer flag",
1);
intFlag.setDefaultValue(2);
const char* argv[] = { "prog", NULL };
Flag::parseFlags(1, argv);
assert(intFlag.value == 2);
flags.parseFlags(1, argv);
assert(intFlag.get() == 2);
}
static void testOverriddenIntValue()
{
FlagGroup flags;
IntFlag intFlag(
{ "--intFlag" },
"a global integer flag",
1);
intFlag.setDefaultValue(2);
const char* argv[] = { "prog", "--intFlag=3" };
flags.parseFlags(2, argv);
assert(intFlag.get() == 3);
}
int main(int argc, const char* argv[])
{
testDefaultIntValue();
testOverriddenIntValue();
return 0;
}

View File

@@ -1,8 +1,11 @@
#include "globals.h"
#include "flags.h"
#include "fluxmap.h"
#include "fluxmapreader.h"
#include <sstream>
FlagGroup flags { &fluxmapReaderFlags };
typedef std::vector<unsigned> ivector;
namespace std {
@@ -124,6 +127,8 @@ void test_patternmatchingwithtrailingzeros()
int main(int argc, const char* argv[])
{
flags.parseFlags(0, NULL);
test_patternconstruction();
test_patternmatchingwithouttrailingzeros();
test_patternmatchingwithtrailingzeros();