tageditor/cli/helper.h

315 lines
10 KiB
C
Raw Normal View History

2017-01-15 21:43:46 +01:00
#ifndef CLI_HELPER
#define CLI_HELPER
#include "../application/knownfieldmodel.h"
2017-01-15 21:43:46 +01:00
#include <tagparser/tag.h>
#include <c++utilities/application/commandlineutils.h>
#include <c++utilities/chrono/datetime.h>
#include <c++utilities/chrono/timespan.h>
#include <c++utilities/conversion/stringconversion.h>
#include <c++utilities/misc/traits.h>
2017-01-15 21:43:46 +01:00
#include <functional>
#include <type_traits>
2018-03-07 01:18:01 +01:00
#include <unordered_map>
#include <vector>
2017-01-15 21:43:46 +01:00
namespace ApplicationUtilities {
class Argument;
}
2018-03-06 23:10:13 +01:00
namespace TagParser {
2017-01-15 21:43:46 +01:00
class MediaFileInfo;
2018-03-06 02:04:35 +01:00
class Diagnostics;
class AbortableProgressFeedback;
2017-01-15 21:43:46 +01:00
enum class TagUsage;
enum class ElementPosition;
2018-03-07 01:18:01 +01:00
} // namespace TagParser
2017-01-15 21:43:46 +01:00
2018-03-06 23:10:13 +01:00
using namespace TagParser;
2017-01-15 21:43:46 +01:00
namespace Cli {
// define enums, operators and structs to handle specified field denotations
2018-03-07 01:18:01 +01:00
enum class DenotationType { Normal, Increment, File };
2017-01-15 21:43:46 +01:00
constexpr TagType operator|(TagType lhs, TagType rhs)
2017-01-15 21:43:46 +01:00
{
return static_cast<TagType>(static_cast<unsigned int>(lhs) | static_cast<unsigned int>(rhs));
}
constexpr TagType operator&(TagType lhs, TagType rhs)
2017-01-15 21:43:46 +01:00
{
return static_cast<TagType>(static_cast<unsigned int>(lhs) & static_cast<unsigned int>(rhs));
}
2018-07-11 13:18:36 +02:00
constexpr TagType &operator|=(TagType &lhs, TagType rhs)
2017-01-15 21:43:46 +01:00
{
return lhs = static_cast<TagType>(static_cast<unsigned int>(lhs) | static_cast<unsigned int>(rhs));
}
2018-03-07 01:18:01 +01:00
class FieldId {
2017-06-14 00:09:10 +02:00
friend struct std::hash<FieldId>;
public:
2017-06-14 00:09:10 +02:00
FieldId(KnownField m_knownField = KnownField::Invalid, const char *denotation = nullptr, std::size_t denotationSize = 0);
static FieldId fromTagDenotation(const char *denotation, std::size_t denotationSize);
static FieldId fromTrackDenotation(const char *denotation, std::size_t denotationSize);
2018-03-07 01:18:01 +01:00
bool operator==(const FieldId &other) const;
KnownField knownField() const;
const char *name() const;
2017-06-14 00:09:10 +02:00
bool denotes(const char *knownDenotation) const;
const std::string &denotation() const;
std::pair<std::vector<const TagValue *>, bool> values(const Tag *tag, TagType tagType) const;
bool setValues(Tag *tag, TagType tagType, const std::vector<TagValue> &values) const;
private:
using GetValuesForNativeFieldType = std::function<std::pair<std::vector<const TagValue *>, bool>(const Tag *, TagType)>;
2018-07-11 13:18:36 +02:00
using SetValuesForNativeFieldType = std::function<bool(Tag *, TagType, const std::vector<TagValue> &)>;
2018-03-07 01:18:01 +01:00
FieldId(const char *nativeField, std::size_t nativeFieldSize, const GetValuesForNativeFieldType &valuesForNativeField,
const SetValuesForNativeFieldType &setValuesForNativeField);
template <class ConcreteTag, TagType tagTypeMask = ConcreteTag::tagType>
static FieldId fromNativeField(const char *nativeFieldId, std::size_t nativeFieldIdSize);
KnownField m_knownField;
2017-06-14 00:09:10 +02:00
std::string m_denotation;
std::string m_nativeField;
GetValuesForNativeFieldType m_valuesForNativeField;
SetValuesForNativeFieldType m_setValuesForNativeField;
2017-01-16 22:58:15 +01:00
};
2018-03-07 01:18:01 +01:00
inline FieldId::FieldId(KnownField knownField, const char *denotation, std::size_t denotationSize)
: m_knownField(knownField)
, m_denotation(denotation, denotationSize)
{
}
2017-01-16 22:58:15 +01:00
2018-03-07 01:18:01 +01:00
inline bool FieldId::operator==(const FieldId &other) const
{
2017-06-14 00:09:10 +02:00
return (m_knownField == other.m_knownField || m_denotation == other.m_denotation) && m_nativeField == other.m_nativeField;
}
inline KnownField FieldId::knownField() const
{
return m_knownField;
}
2017-06-14 00:09:10 +02:00
inline const char *FieldId::name() const
{
2017-06-14 00:09:10 +02:00
return !m_nativeField.empty() ? m_nativeField.data() : Settings::KnownFieldModel::fieldName(m_knownField);
}
2017-06-14 00:09:10 +02:00
inline bool FieldId::denotes(const char *knownDenotation) const
{
return !std::strncmp(m_denotation.data(), knownDenotation, m_denotation.size());
}
inline const std::string &FieldId::denotation() const
{
2017-06-14 00:09:10 +02:00
return m_denotation;
}
2017-01-16 22:58:15 +01:00
2018-03-07 01:18:01 +01:00
struct FieldScope {
2017-01-15 21:43:46 +01:00
FieldScope(KnownField field = KnownField::Invalid, TagType tagType = TagType::Unspecified, TagTarget tagTarget = TagTarget());
2018-03-07 01:18:01 +01:00
bool operator==(const FieldScope &other) const;
2017-06-14 00:09:10 +02:00
bool isTrack() const;
FieldId field;
2017-01-15 21:43:46 +01:00
TagType tagType;
TagTarget tagTarget;
2017-06-14 00:09:10 +02:00
bool allTracks;
std::vector<uint64> trackIds;
2017-01-15 21:43:46 +01:00
};
2018-03-07 01:18:01 +01:00
inline FieldScope::FieldScope(KnownField field, TagType tagType, TagTarget tagTarget)
: field(field)
, tagType(tagType)
, tagTarget(tagTarget)
, allTracks(false)
{
}
2017-01-15 21:43:46 +01:00
2018-03-07 01:18:01 +01:00
inline bool FieldScope::operator==(const FieldScope &other) const
2017-01-15 21:43:46 +01:00
{
return field == other.field && tagType == other.tagType && tagTarget == other.tagTarget;
}
2017-06-14 00:09:10 +02:00
inline bool FieldScope::isTrack() const
{
return allTracks || !trackIds.empty();
}
2018-03-07 01:18:01 +01:00
struct FieldValue {
2017-01-15 21:43:46 +01:00
FieldValue(DenotationType type, unsigned int fileIndex, const char *value);
DenotationType type;
unsigned int fileIndex;
std::string value;
};
2018-03-07 01:18:01 +01:00
inline FieldValue::FieldValue(DenotationType type, unsigned int fileIndex, const char *value)
: type(type)
, fileIndex(fileIndex)
, value(value)
{
2018-03-07 01:18:01 +01:00
}
class InterruptHandler {
public:
InterruptHandler(std::function<void()> handler);
~InterruptHandler();
private:
static void handler(int signum);
static std::function<void()> s_handler;
static bool s_handlerRegistered;
};
2018-03-07 01:18:01 +01:00
} // namespace Cli
2017-01-15 21:43:46 +01:00
// define hash functions for custom data types
namespace std {
using namespace Cli;
2018-03-07 01:18:01 +01:00
template <> struct hash<KnownField> {
2017-01-15 21:43:46 +01:00
std::size_t operator()(const KnownField &ids) const
{
using type = typename std::underlying_type<KnownField>::type;
return std::hash<type>()(static_cast<type>(ids));
}
};
2018-03-07 01:18:01 +01:00
template <> struct hash<TagType> {
2017-01-15 21:43:46 +01:00
std::size_t operator()(const TagType &ids) const
{
using type = typename std::underlying_type<TagType>::type;
return std::hash<type>()(static_cast<type>(ids));
}
};
2018-03-07 01:18:01 +01:00
template <> struct hash<TagTarget::IdContainerType> {
2017-01-15 21:43:46 +01:00
std::size_t operator()(const TagTarget::IdContainerType &ids) const
{
using std::hash;
auto seed = ids.size();
2018-03-07 01:18:01 +01:00
for (auto id : ids) {
2017-01-15 21:43:46 +01:00
seed ^= id + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}
return seed;
}
};
2018-03-07 01:18:01 +01:00
template <> struct hash<TagTarget> {
std::size_t operator()(const TagTarget &target) const
2017-01-15 21:43:46 +01:00
{
using std::hash;
2018-03-07 01:18:01 +01:00
return ((hash<uint64>()(target.level()) ^ (hash<TagTarget::IdContainerType>()(target.tracks()) << 1)) >> 1)
^ (hash<TagTarget::IdContainerType>()(target.attachments()) << 1);
2017-01-15 21:43:46 +01:00
}
};
2018-03-07 01:18:01 +01:00
template <> struct hash<FieldId> {
std::size_t operator()(const FieldId &id) const
{
using std::hash;
2017-06-14 00:09:10 +02:00
return ((id.knownField() != KnownField::Invalid) ? hash<KnownField>()(id.knownField()) : hash<string>()(id.denotation()))
2018-03-07 01:18:01 +01:00
^ (hash<string>()(id.m_nativeField) << 1);
}
};
2018-03-07 01:18:01 +01:00
template <> struct hash<FieldScope> {
std::size_t operator()(const FieldScope &scope) const
2017-01-15 21:43:46 +01:00
{
using std::hash;
2018-03-07 01:18:01 +01:00
return (hash<FieldId>()(scope.field) ^ (hash<TagType>()(scope.tagType) << 1) >> 1)
^ (hash<TagTarget>()(scope.tagTarget) ^ (static_cast<unsigned long>(scope.allTracks) << 4)
^ (hash<vector<uint64>>()(scope.trackIds) << 1) >> 1);
2017-01-15 21:43:46 +01:00
}
};
2018-03-07 01:18:01 +01:00
} // namespace std
2017-01-15 21:43:46 +01:00
namespace Cli {
2018-03-07 01:18:01 +01:00
struct FieldValues {
2017-06-14 00:09:10 +02:00
std::vector<FieldValue> allValues;
std::vector<FieldValue *> relevantValues;
};
2018-07-11 13:18:36 +02:00
using FieldDenotations = std::unordered_map<FieldScope, FieldValues>;
2017-01-15 21:43:46 +01:00
// declare/define actual helpers
constexpr bool isDigit(char c)
{
return c >= '0' && c <= '9';
}
std::string incremented(const std::string &str, unsigned int toIncrement = 1);
2018-03-06 23:10:13 +01:00
void printDiagMessages(const TagParser::Diagnostics &diag, const char *head = nullptr, bool beVerbose = false);
2017-01-15 21:43:46 +01:00
void printProperty(const char *propName, const char *value, const char *suffix = nullptr, ApplicationUtilities::Indentation indentation = 4);
2018-03-07 01:18:01 +01:00
void printProperty(
const char *propName, ElementPosition elementPosition, const char *suffix = nullptr, ApplicationUtilities::Indentation indentation = 4);
2017-01-15 21:43:46 +01:00
2018-03-07 01:18:01 +01:00
inline void printProperty(
const char *propName, const std::string &value, const char *suffix = nullptr, ApplicationUtilities::Indentation indentation = 4)
2017-01-15 21:43:46 +01:00
{
printProperty(propName, value.data(), suffix, indentation);
}
extern ChronoUtilities::TimeSpanOutputFormat timeSpanOutputFormat;
2018-03-07 01:18:01 +01:00
inline void printProperty(
const char *propName, ChronoUtilities::TimeSpan timeSpan, const char *suffix = nullptr, ApplicationUtilities::Indentation indentation = 4)
2017-01-15 21:43:46 +01:00
{
2018-03-07 01:18:01 +01:00
if (!timeSpan.isNull()) {
printProperty(propName, timeSpan.toString(timeSpanOutputFormat), suffix, indentation);
2017-01-15 21:43:46 +01:00
}
}
2018-03-07 01:18:01 +01:00
inline void printProperty(
const char *propName, ChronoUtilities::DateTime dateTime, const char *suffix = nullptr, ApplicationUtilities::Indentation indentation = 4)
2017-01-15 21:43:46 +01:00
{
2018-03-07 01:18:01 +01:00
if (!dateTime.isNull()) {
2017-01-15 21:43:46 +01:00
printProperty(propName, dateTime.toString(), suffix, indentation);
}
}
template <typename NumberType, Traits::EnableIfAny<std::is_integral<NumberType>, std::is_floating_point<NumberType>> * = nullptr>
2018-03-07 01:18:01 +01:00
inline void printProperty(
const char *propName, const NumberType value, const char *suffix = nullptr, bool force = false, ApplicationUtilities::Indentation indentation = 4)
2017-01-15 21:43:46 +01:00
{
2018-03-07 01:18:01 +01:00
if (value != 0 || force) {
printProperty(propName, ConversionUtilities::numberToString<NumberType>(value), suffix, indentation);
2017-01-15 21:43:46 +01:00
}
}
void printField(const FieldScope &scope, const Tag *tag, TagType tagType, bool skipEmpty);
void printNativeFields(const Tag *tag);
2017-01-16 22:58:15 +01:00
2018-03-07 01:18:01 +01:00
ChronoUtilities::TimeSpanOutputFormat parseTimeSpanOutputFormat(
const ApplicationUtilities::Argument &usageArg, ChronoUtilities::TimeSpanOutputFormat defaultFormat);
2017-01-15 21:43:46 +01:00
TagUsage parseUsageDenotation(const ApplicationUtilities::Argument &usageArg, TagUsage defaultUsage);
TagTextEncoding parseEncodingDenotation(const ApplicationUtilities::Argument &encodingArg, TagTextEncoding defaultEncoding);
2018-03-07 01:18:01 +01:00
ElementPosition parsePositionDenotation(
const ApplicationUtilities::Argument &posArg, const ApplicationUtilities::Argument &valueArg, ElementPosition defaultPos);
2017-01-15 21:43:46 +01:00
uint64 parseUInt64(const ApplicationUtilities::Argument &arg, uint64 defaultValue);
TagTarget::IdContainerType parseIds(const std::string &concatenatedIds);
bool applyTargetConfiguration(TagTarget &target, const std::string &configStr);
FieldDenotations parseFieldDenotations(const ApplicationUtilities::Argument &fieldsArg, bool readOnly);
2017-05-18 02:32:51 +02:00
std::string tagName(const Tag *tag);
2017-06-14 00:09:10 +02:00
bool stringToBool(const std::string &str);
extern bool logLineFinalized;
2018-03-06 23:10:13 +01:00
void logNextStep(const TagParser::AbortableProgressFeedback &progress);
void logStepPercentage(const TagParser::AbortableProgressFeedback &progress);
void finalizeLog();
2018-03-07 01:18:01 +01:00
} // namespace Cli
2017-01-15 21:43:46 +01:00
#endif // CLI_HELPER