Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Printf formatters (String and Int types) #19

Merged
merged 4 commits into from
Mar 29, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions lib/Variables/PrintfFormatterNumeric.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#include <VariableFormatters.h>
#include <ArduinoJson.h>

static const char FORMAT_ARG_NAME[] = "format";

PrintfFormatterNumeric::PrintfFormatterNumeric(const String& formatSchema)
: formatSchema(formatSchema)
{ }

std::shared_ptr<const PrintfFormatterNumeric> PrintfFormatterNumeric::build(JsonObject args) {
String formatSchema;

if (args.containsKey(FORMAT_ARG_NAME)) {
formatSchema = args[FORMAT_ARG_NAME].as<const char*>();
// In case someone does a schema that can crash the ESP
formatSchema.replace("%s", "ERR");
// Replacing the double percent in case the user needs a percent sign in the output
// Replacing it with a (hopefully) impossible character should make sure that it doesn't get un-replaced by anything that is needed.
// \a is the bell/ding that can flash your console/cause it to make a sound.
formatSchema.replace("%%", "\a");
// This makes sure that if they add more than one formatter, it will only use the first and only argument.
formatSchema.replace("%", "%1$");
// Undoing the first replace so the escaped percent can be printed
formatSchema.replace("\a", "%%");
} else {
formatSchema = "%1$d";
}

return std::shared_ptr<const PrintfFormatterNumeric>(new PrintfFormatterNumeric(formatSchema));
}

String PrintfFormatterNumeric::format(const String &value) const {
int numericValue = value.toInt();

char buffer[120];
snprintf(buffer, sizeof(buffer), formatSchema.c_str(), numericValue);

return buffer;
}
34 changes: 34 additions & 0 deletions lib/Variables/PrintfFormatterString.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
#include <VariableFormatters.h>
#include <ArduinoJson.h>

static const char FORMAT_ARG_NAME[] = "format";

PrintfFormatterString::PrintfFormatterString(const String& formatSchema)
: formatSchema(formatSchema)
{ }

std::shared_ptr<const PrintfFormatterString> PrintfFormatterString::build(JsonObject args) {
String formatSchema;

if (args.containsKey(FORMAT_ARG_NAME)) {
formatSchema = args[FORMAT_ARG_NAME].as<const char*>();
// Replacing the double percent in case the user needs a percent sign in the output
// Replacing it with a (hopefully) impossible character should make sure that it doesn't get un-replaced by anything that is needed.
formatSchema.replace("%%", "\a");
// This makes sure that if they add more than one formatter, it will only use the first and only argument.
formatSchema.replace("%", "%1$");
// Undoing the first replace so the escaped percent can be printed
formatSchema.replace("\a", "%%");
} else {
formatSchema = "%1$s";
}

return std::shared_ptr<const PrintfFormatterString>(new PrintfFormatterString(formatSchema));
}

String PrintfFormatterString::format(const String &value) const {
char buffer[120];
snprintf(buffer, sizeof(buffer), formatSchema.c_str(), value.c_str());

return buffer;
}
4 changes: 4 additions & 0 deletions lib/Variables/VariableFormatterFactory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,10 @@ VariableFormatterFactory::_createInternal(
}

return std::make_shared<RatioVariableFormatter>(base);
} else if (formatterDef.equalsIgnoreCase("pfstring")) {
return PrintfFormatterString::build(formatterArgs);
} else if (formatterDef.equalsIgnoreCase("pfnumeric")) {
return PrintfFormatterNumeric::build(formatterArgs);
} else {
return defaultFormatter;
}
Expand Down
22 changes: 22 additions & 0 deletions lib/Variables/VariableFormatters.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,28 @@ class TimeVariableFormatter : public VariableFormatter {
Timezone& timezone;
};

class PrintfFormatterNumeric : public VariableFormatter {
public:
PrintfFormatterNumeric(const String& formatSchema);

virtual String format(const String& value) const;
static std::shared_ptr<const PrintfFormatterNumeric> build(JsonObject args);

protected:
String formatSchema;
};

class PrintfFormatterString : public VariableFormatter {
public:
PrintfFormatterString(const String& formatSchema);

virtual String format(const String& value) const;
static std::shared_ptr<const PrintfFormatterString> build(JsonObject args);

protected:
String formatSchema;
};

class CasesVariableFormatter : public VariableFormatter {
public:
CasesVariableFormatter(JsonObject args);
Expand Down
46 changes: 43 additions & 3 deletions template.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -139,15 +139,19 @@
"time",
"round",
"cases",
"ratio"
"ratio",
"pfstring",
"pfnumeric"
],
"enumNames": [
"Pre-Defined Formatter",
"Identity (No-Op)",
"Time (strftime)",
"Round",
"Cases",
"Ratio"
"Ratio",
"Printf (String)",
"Printf (int)"
]
},
"args": {
Expand Down Expand Up @@ -271,7 +275,43 @@
}
}
}
}
},
{
"properties": {
"type": {
"enum": [
"pfstring"
]
},
"args": {
"type": "object",
"properties": {
"format": {
"title": "Printf (String)",
"type": "string"
}
}
}
}
},
{
"properties": {
"type": {
"enum": [
"pfnumeric"
]
},
"args": {
"type": "object",
"properties": {
"format": {
"title": "Printf (int)",
"type": "string"
}
}
}
}
}
]
}
}
Expand Down
38 changes: 36 additions & 2 deletions web/src/templates/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -218,14 +218,16 @@ const Definitions = {
type: {
title: "Type",
type: "string",
enum: ["ref", "identity", "time", "round", "cases", "ratio"],
enum: ["ref", "identity", "time", "round", "cases", "ratio", "pfstring", "pfnumeric"],
enumNames: [
"Pre-Defined Formatter",
"Identity (No-Op)",
"Time (strftime)",
"Round",
"Cases",
"Ratio"
"Ratio",
"Printf (String)",
"Printf (int)"
]
},
args: {
Expand Down Expand Up @@ -335,6 +337,38 @@ const Definitions = {
}
}
}
},
{
properties: {
type: {
enum: ["pfstring"]
},
args: {
type: "object",
properties: {
format: {
title: "Printf (String)",
type: "string"
}
}
}
}
},
{
properties: {
type: {
enum: ["pfnumeric"]
},
args: {
type: "object",
properties: {
format: {
title: "Printf (int)",
type: "string"
}
}
}
}
}
]
}
Expand Down