mirror of
https://github.com/pgbackrest/pgbackrest.git
synced 2025-03-03 14:52:21 +02:00
Convert configuration optional rules to pack format.
The previous format was custom for configuration parsing and was not as expressive as the pack format. An immediate benefit is that commands with the same optional rules are merged. Defaults are now represented correctly (not multiplied), which simplifies the option default functions used by help.
This commit is contained in:
parent
360cff94e4
commit
6b9e19d423
@ -31,8 +31,12 @@ Option type constants
|
||||
***********************************************************************************************************************************/
|
||||
STRING_EXTERN(OPT_TYPE_BOOLEAN_STR, OPT_TYPE_BOOLEAN);
|
||||
STRING_EXTERN(OPT_TYPE_HASH_STR, OPT_TYPE_HASH);
|
||||
STRING_EXTERN(OPT_TYPE_INTEGER_STR, OPT_TYPE_INTEGER);
|
||||
STRING_EXTERN(OPT_TYPE_LIST_STR, OPT_TYPE_LIST);
|
||||
STRING_EXTERN(OPT_TYPE_PATH_STR, OPT_TYPE_PATH);
|
||||
STRING_EXTERN(OPT_TYPE_SIZE_STR, OPT_TYPE_SIZE);
|
||||
STRING_EXTERN(OPT_TYPE_STRING_STR, OPT_TYPE_STRING);
|
||||
STRING_EXTERN(OPT_TYPE_STRING_ID_STR, OPT_TYPE_STRING_ID);
|
||||
STRING_EXTERN(OPT_TYPE_TIME_STR, OPT_TYPE_TIME);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
|
@ -33,10 +33,18 @@ Option type constants
|
||||
STRING_DECLARE(OPT_TYPE_BOOLEAN_STR);
|
||||
#define OPT_TYPE_HASH "hash"
|
||||
STRING_DECLARE(OPT_TYPE_HASH_STR);
|
||||
#define OPT_TYPE_INTEGER "integer"
|
||||
STRING_DECLARE(OPT_TYPE_INTEGER_STR);
|
||||
#define OPT_TYPE_LIST "list"
|
||||
STRING_DECLARE(OPT_TYPE_LIST_STR);
|
||||
#define OPT_TYPE_PATH "path"
|
||||
STRING_DECLARE(OPT_TYPE_PATH_STR);
|
||||
#define OPT_TYPE_SIZE "size"
|
||||
STRING_DECLARE(OPT_TYPE_SIZE_STR);
|
||||
#define OPT_TYPE_STRING "string"
|
||||
STRING_DECLARE(OPT_TYPE_STRING_STR);
|
||||
#define OPT_TYPE_STRING_ID "stringId"
|
||||
STRING_DECLARE(OPT_TYPE_STRING_ID_STR);
|
||||
#define OPT_TYPE_TIME "time"
|
||||
STRING_DECLARE(OPT_TYPE_TIME_STR);
|
||||
|
||||
|
@ -297,128 +297,227 @@ bldCfgRenderLf(String *const config, const bool lf)
|
||||
strCatZ(config, "\n");
|
||||
}
|
||||
|
||||
static const String *
|
||||
bldCfgRenderValue(const String *const type, const String *const value)
|
||||
// Helper to get var-128 encoding size
|
||||
static size_t
|
||||
bldCfgRenderVar128Size(uint64_t value)
|
||||
{
|
||||
// Translate boolean values
|
||||
if (strEq(type, OPT_TYPE_BOOLEAN_STR))
|
||||
size_t result = 1;
|
||||
|
||||
while (value >= 0x80)
|
||||
{
|
||||
if (strEq(value, FALSE_STR))
|
||||
return ZERO_STR;
|
||||
|
||||
CHECK(strEq(value, TRUE_STR));
|
||||
return strNewZ("1");
|
||||
value >>= 7;
|
||||
result++;
|
||||
}
|
||||
// Translate time values
|
||||
else if (strEq(type, OPT_TYPE_TIME_STR))
|
||||
return strNewFmt("%" PRId64, (int64_t)(cvtZToDouble(strZ(value)) * 1000));
|
||||
|
||||
return value;
|
||||
return result;
|
||||
}
|
||||
|
||||
// Helper to render enum string
|
||||
static String *
|
||||
bldCfgRenderEnumStr(const String *const source)
|
||||
{
|
||||
String *const result = strNew();
|
||||
bool priorSpecial = false;
|
||||
|
||||
for (unsigned int sourceIdx = 0; sourceIdx < strSize(source); sourceIdx++)
|
||||
{
|
||||
switch (strZ(source)[sourceIdx])
|
||||
{
|
||||
case '"':
|
||||
case '/':
|
||||
case ' ':
|
||||
case '.':
|
||||
{
|
||||
if (sourceIdx != 0 && !priorSpecial)
|
||||
strCatChr(result, '_');
|
||||
|
||||
switch (strZ(source)[sourceIdx])
|
||||
{
|
||||
case '"':
|
||||
strCatZ(result, "QT");
|
||||
break;
|
||||
|
||||
case '/':
|
||||
strCatZ(result, "FS");
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
strCatZ(result, "SP");
|
||||
break;
|
||||
|
||||
case '.':
|
||||
strCatZ(result, "DT");
|
||||
break;
|
||||
}
|
||||
|
||||
if (sourceIdx != strSize(source) - 1)
|
||||
strCatChr(result, '_');
|
||||
|
||||
priorSpecial = true;
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
strCatChr(result, strZ(source)[sourceIdx]);
|
||||
priorSpecial = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Helper to render scalars
|
||||
static String *
|
||||
bldCfgRenderScalar(const String *const scalar, const String *const optType)
|
||||
{
|
||||
if (strEq(optType, OPT_TYPE_STRING_ID_STR))
|
||||
return strNewFmt("PARSE_RULE_VAL_STRID(%s)", strZ(bldEnum("parseRuleValStrId", scalar)));
|
||||
|
||||
if (strEq(optType, OPT_TYPE_STRING_STR))
|
||||
return strNewFmt("PARSE_RULE_VAL_STR(parseRuleValStr%s)", strZ(bldCfgRenderEnumStr(scalar)));
|
||||
|
||||
if (strEq(optType, OPT_TYPE_BOOLEAN_STR))
|
||||
return strNewFmt("PARSE_RULE_VAL_BOOL_%s", strEqZ(scalar, "true") ? "TRUE" : "FALSE");
|
||||
|
||||
int64_t value = 0;
|
||||
|
||||
if (strEq(optType, OPT_TYPE_TIME_STR))
|
||||
{
|
||||
value = (int64_t)(cvtZToDouble(strZ(scalar)) * 1000);
|
||||
}
|
||||
else
|
||||
{
|
||||
CHECK(strEq(optType, OPT_TYPE_SIZE_STR) || strEq(optType, OPT_TYPE_INTEGER_STR));
|
||||
|
||||
value = cvtZToInt64(strZ(scalar));
|
||||
}
|
||||
|
||||
return strNewFmt("PARSE_RULE_VAL_INT(%s)", strZ(bldEnum("parseRuleValInt", strNewFmt("%" PRId64, value))));
|
||||
}
|
||||
|
||||
// Helper to render validity
|
||||
static String *
|
||||
bldCfgRenderValid(const BldCfgOptionDepend *const depend)
|
||||
{
|
||||
ASSERT(depend != NULL);
|
||||
|
||||
String *const result = strNew();
|
||||
|
||||
strCatFmt(
|
||||
result,
|
||||
" PARSE_RULE_OPTIONAL_DEPEND\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_OPT(%s),\n",
|
||||
strZ(bldEnum("cfgOpt", depend->option->name)));
|
||||
|
||||
if (depend->valueList != NULL)
|
||||
{
|
||||
for (unsigned int valueIdx = 0; valueIdx < strLstSize(depend->valueList); valueIdx++)
|
||||
{
|
||||
strCatFmt(
|
||||
result,
|
||||
" %s,\n",
|
||||
strZ(
|
||||
bldCfgRenderScalar(
|
||||
strLstGet(depend->valueList, valueIdx),
|
||||
strEq(depend->option->type, OPT_TYPE_STRING_STR) ? OPT_TYPE_STRING_ID_STR : depend->option->type)));
|
||||
}
|
||||
}
|
||||
|
||||
strCatZ(
|
||||
result,
|
||||
" )");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Helper to render allow range
|
||||
static String *
|
||||
bldCfgRenderAllowRange(const String *const allowRangeMin, const String *const allowRangeMax, const String *const optType)
|
||||
{
|
||||
ASSERT(allowRangeMin != NULL);
|
||||
ASSERT(allowRangeMax != NULL);
|
||||
ASSERT(optType != NULL);
|
||||
|
||||
return strNewFmt(
|
||||
" PARSE_RULE_OPTIONAL_ALLOW_RANGE\n"
|
||||
" (\n"
|
||||
" %s,\n"
|
||||
" %s,\n"
|
||||
" )",
|
||||
strZ(bldCfgRenderScalar(allowRangeMin, optType)),
|
||||
strZ(bldCfgRenderScalar(allowRangeMax, optType)));
|
||||
}
|
||||
|
||||
// Helper to render allow list
|
||||
static bool
|
||||
bldCfgRenderAllowList(String *const config, const StringList *const allowList, const bool command)
|
||||
static String *
|
||||
bldCfgRenderAllowList(const StringList *const allowList, const String *const optType)
|
||||
{
|
||||
if (allowList != NULL)
|
||||
ASSERT(allowList != NULL);
|
||||
ASSERT(optType != NULL);
|
||||
|
||||
String *const result = strNew();
|
||||
|
||||
strCatZ(
|
||||
result,
|
||||
" PARSE_RULE_OPTIONAL_ALLOW_LIST\n"
|
||||
" (\n");
|
||||
|
||||
for (unsigned int allowIdx = 0; allowIdx < strLstSize(allowList); allowIdx++)
|
||||
{
|
||||
const char *indent = command ? " " : " ";
|
||||
const String *const value = strLstGet(allowList, allowIdx);
|
||||
|
||||
strCatFmt(
|
||||
config,
|
||||
"%sPARSE_RULE_OPTION_OPTIONAL_ALLOW_LIST\n"
|
||||
"%s(\n",
|
||||
indent, indent);
|
||||
|
||||
for (unsigned int allowIdx = 0; allowIdx < strLstSize(allowList); allowIdx++)
|
||||
{
|
||||
strCatFmt(
|
||||
config,
|
||||
"%s \"%s\"%s\n",
|
||||
indent, strZ(strLstGet(allowList, allowIdx)),
|
||||
allowIdx < strLstSize(allowList) - 1 ? "," : "");
|
||||
}
|
||||
|
||||
strCatFmt(config, "%s),\n", indent);
|
||||
|
||||
return true;
|
||||
strCatFmt(result, " %s,\n", strZ(bldCfgRenderScalar(value, optType)));
|
||||
}
|
||||
|
||||
return false;
|
||||
strCatZ(result, " )");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Helper to render default
|
||||
static bool
|
||||
static String *
|
||||
bldCfgRenderDefault(
|
||||
String *const config, const String *const type, const String *const defaultValue,
|
||||
const bool defaultLiteral, const bool command, bool multi)
|
||||
const String *const defaultValue, const bool defaultLiteral, const String *const optType)
|
||||
{
|
||||
if (defaultValue != NULL)
|
||||
ASSERT(defaultValue != NULL);
|
||||
ASSERT(optType != NULL);
|
||||
|
||||
String *const result = strNew();
|
||||
|
||||
strCatZ(
|
||||
result,
|
||||
" PARSE_RULE_OPTIONAL_DEFAULT\n"
|
||||
" (\n");
|
||||
|
||||
if (!strEq(optType, OPT_TYPE_STRING_STR) && !strEq(optType, OPT_TYPE_PATH_STR) && !strEq(optType, OPT_TYPE_STRING_ID_STR))
|
||||
strCatFmt(result, " %s,\n", strZ(bldCfgRenderScalar(defaultValue, optType)));
|
||||
|
||||
if (!strEq(optType, OPT_TYPE_BOOLEAN_STR))
|
||||
{
|
||||
const char *indent = command ? " " : " ";
|
||||
|
||||
bldCfgRenderLf(config, multi);
|
||||
|
||||
strCatFmt(
|
||||
config,
|
||||
"%sPARSE_RULE_OPTION_OPTIONAL_DEFAULT(%s%s%s),\n",
|
||||
indent, defaultLiteral ? "" : "\"", strZ(bldCfgRenderValue(type, defaultValue)), defaultLiteral ? "" : "\"");
|
||||
|
||||
return false;
|
||||
result,
|
||||
" %s,\n",
|
||||
strZ(
|
||||
bldCfgRenderScalar(
|
||||
strNewFmt("%s%s%s", defaultLiteral ? "" : "\"", strZ(defaultValue), defaultLiteral ? "" : "\""),
|
||||
OPT_TYPE_STRING_STR)));
|
||||
}
|
||||
|
||||
return multi;
|
||||
}
|
||||
strCatZ(result, " )");
|
||||
|
||||
// Helper to render depend
|
||||
static bool
|
||||
bldCfgRenderDepend(String *const config, const BldCfgOptionDepend *const depend, const bool command, const bool multi)
|
||||
{
|
||||
if (depend != NULL)
|
||||
{
|
||||
const char *indent = command ? " " : " ";
|
||||
|
||||
bldCfgRenderLf(config, multi);
|
||||
|
||||
if (depend->valueList != NULL)
|
||||
{
|
||||
strCatFmt(
|
||||
config,
|
||||
"%sPARSE_RULE_OPTION_OPTIONAL_DEPEND_LIST\n"
|
||||
"%s(\n"
|
||||
"%s %s,\n",
|
||||
indent, indent, indent, strZ(bldEnum("cfgOpt", depend->option->name)));
|
||||
|
||||
for (unsigned int valueIdx = 0; valueIdx < strLstSize(depend->valueList); valueIdx++)
|
||||
{
|
||||
strCatFmt(
|
||||
config, "%s \"%s\"%s\n", indent,
|
||||
strZ(bldCfgRenderValue(depend->option->type, strLstGet(depend->valueList, valueIdx))),
|
||||
valueIdx < strLstSize(depend->valueList) - 1 ? "," : "");
|
||||
}
|
||||
|
||||
strCatFmt(config, "%s),\n", indent);
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
strCatFmt(
|
||||
config,
|
||||
"%sPARSE_RULE_OPTION_OPTIONAL_DEPEND(%s),\n",
|
||||
indent, strZ(bldEnum("cfgOpt", depend->option->name)));
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return multi;
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
bldCfgRenderParseAutoC(const Storage *const storageRepo, const BldCfg bldCfg)
|
||||
{
|
||||
String *const config = bldHeader(CONFIG_MODULE, PARSE_AUTO_COMMENT);
|
||||
String *const config = strNew();
|
||||
|
||||
StringList *const ruleIntList = strLstNew();
|
||||
StringList *const ruleStrList = strLstNew();
|
||||
StringList *const ruleStrIdList = strLstNew();
|
||||
|
||||
// Command parse rules
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
@ -427,7 +526,18 @@ bldCfgRenderParseAutoC(const Storage *const storageRepo, const BldCfg bldCfg)
|
||||
"\n"
|
||||
COMMENT_BLOCK_BEGIN "\n"
|
||||
"Command parse data\n"
|
||||
COMMENT_BLOCK_END "\n"
|
||||
COMMENT_BLOCK_END "\n");
|
||||
|
||||
strCatFmt(
|
||||
config, "%s\n",
|
||||
strZ(
|
||||
bldDefineRender(
|
||||
STRDEF("PARSE_RULE_VAL_CMD(value)"),
|
||||
strNewFmt("PARSE_RULE_U32_%zu(value)", bldCfgRenderVar128Size(lstSize(bldCfg.cmdList) - 1)))));
|
||||
|
||||
strCatFmt(
|
||||
config,
|
||||
"\n"
|
||||
"static const ParseRuleCommand parseRuleCommand[CFG_COMMAND_TOTAL] =\n"
|
||||
"{\n");
|
||||
|
||||
@ -523,7 +633,18 @@ bldCfgRenderParseAutoC(const Storage *const storageRepo, const BldCfg bldCfg)
|
||||
"\n"
|
||||
COMMENT_BLOCK_BEGIN "\n"
|
||||
"Option parse data\n"
|
||||
COMMENT_BLOCK_END "\n"
|
||||
COMMENT_BLOCK_END "\n");
|
||||
|
||||
strCatFmt(
|
||||
config, "%s\n",
|
||||
strZ(
|
||||
bldDefineRender(
|
||||
STRDEF("PARSE_RULE_VAL_OPT(value)"),
|
||||
strNewFmt("PARSE_RULE_U32_%zu(value)", bldCfgRenderVar128Size(lstSize(bldCfg.optList) - 1)))));
|
||||
|
||||
strCatFmt(
|
||||
config,
|
||||
"\n"
|
||||
"static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] =\n"
|
||||
"{\n");
|
||||
|
||||
@ -536,6 +657,8 @@ bldCfgRenderParseAutoC(const Storage *const storageRepo, const BldCfg bldCfg)
|
||||
for (unsigned int optIdx = 0; optIdx < lstSize(bldCfg.optList); optIdx++)
|
||||
{
|
||||
const BldCfgOption *const opt = lstGet(bldCfg.optList, optIdx);
|
||||
StringList *const ruleDataList = strLstNew();
|
||||
bool ruleInt = false;
|
||||
|
||||
bldCfgRenderLf(config, optIdx != 0);
|
||||
|
||||
@ -622,82 +745,293 @@ bldCfgRenderParseAutoC(const Storage *const storageRepo, const BldCfg bldCfg)
|
||||
}
|
||||
}
|
||||
|
||||
// Build optional data
|
||||
String *const configOptional = strNew();
|
||||
// Determine if the option has an allow list. This will decide whether it is treated as a String or StringId. This should be
|
||||
// replaced with a StringId type.
|
||||
bool allowList = opt->allowList != NULL;
|
||||
|
||||
for (unsigned int optCmdIdx = 0; optCmdIdx < lstSize(opt->cmdList); optCmdIdx++)
|
||||
{
|
||||
if (((BldCfgOptionCommand *)lstGet(opt->cmdList, optCmdIdx))->allowList != NULL)
|
||||
allowList = true;
|
||||
}
|
||||
|
||||
// Build default optional rules
|
||||
KeyValue *const optionalDefaultRule = kvNew();
|
||||
const Variant *const ruleDepend = VARSTRDEF("01-depend");
|
||||
const Variant *const ruleAllowRange = VARSTRDEF("02-allow-range");
|
||||
const Variant *const ruleAllowList = VARSTRDEF("03-allow-list");
|
||||
const Variant *const ruleDefault = VARSTRDEF("04-default");
|
||||
const Variant *const ruleRequire = VARSTRDEF("05-require");
|
||||
const Variant *const ruleList[] = {ruleDepend, ruleAllowRange, ruleAllowList, ruleDefault, ruleRequire};
|
||||
|
||||
if (opt->depend)
|
||||
kvAdd(optionalDefaultRule, ruleDepend, VARSTR(bldCfgRenderValid(opt->depend)));
|
||||
|
||||
if (opt->allowRangeMin != NULL)
|
||||
{
|
||||
CHECK(opt->allowRangeMax != NULL);
|
||||
|
||||
const String *allowRangeMin = opt->allowRangeMin;
|
||||
const String *allowRangeMax = opt->allowRangeMax;
|
||||
kvAdd(
|
||||
optionalDefaultRule, ruleAllowRange,
|
||||
VARSTR(bldCfgRenderAllowRange(opt->allowRangeMin, opt->allowRangeMax, opt->type)));
|
||||
|
||||
if (strEq(opt->type, OPT_TYPE_TIME_STR))
|
||||
{
|
||||
allowRangeMin = strNewFmt("%" PRId64, (int64_t)(cvtZToDouble(strZ(allowRangeMin)) * 1000));
|
||||
allowRangeMax = strNewFmt("%" PRId64, (int64_t)(cvtZToDouble(strZ(allowRangeMax)) * 1000));
|
||||
strLstAddIfMissing(ruleDataList, strNewFmt("%" PRId64, (int64_t)(cvtZToDouble(strZ(opt->allowRangeMin)) * 1000)));
|
||||
strLstAddIfMissing(ruleDataList, strNewFmt("%" PRId64, (int64_t)(cvtZToDouble(strZ(opt->allowRangeMax)) * 1000)));
|
||||
}
|
||||
else
|
||||
{
|
||||
strLstAddIfMissing(ruleDataList, opt->allowRangeMin);
|
||||
strLstAddIfMissing(ruleDataList, opt->allowRangeMax);
|
||||
}
|
||||
|
||||
strCatFmt(
|
||||
configOptional,
|
||||
" PARSE_RULE_OPTION_OPTIONAL_ALLOW_RANGE(%s, %s),\n",
|
||||
strZ(allowRangeMin), strZ(allowRangeMax));
|
||||
}
|
||||
|
||||
bool multi = bldCfgRenderAllowList(configOptional, opt->allowList, false);
|
||||
multi = bldCfgRenderDepend(configOptional, opt->depend, false, multi);
|
||||
multi = bldCfgRenderDefault(configOptional, opt->type, opt->defaultValue, opt->defaultLiteral, false, multi);
|
||||
if (opt->allowList != NULL)
|
||||
{
|
||||
kvAdd(
|
||||
optionalDefaultRule, ruleAllowList,
|
||||
VARSTR(
|
||||
bldCfgRenderAllowList(
|
||||
opt->allowList, strEq(opt->type, OPT_TYPE_STRING_STR) ? OPT_TYPE_STRING_ID_STR : opt->type)));
|
||||
|
||||
for (unsigned int allowIdx = 0; allowIdx < strLstSize(opt->allowList); allowIdx++)
|
||||
strLstAddIfMissing(ruleDataList, strLstGet(opt->allowList, allowIdx));
|
||||
}
|
||||
|
||||
if (opt->defaultValue != NULL)
|
||||
{
|
||||
kvAdd(
|
||||
optionalDefaultRule, ruleDefault,
|
||||
VARSTR(
|
||||
bldCfgRenderDefault(
|
||||
opt->defaultValue, opt->defaultLiteral,
|
||||
strEq(opt->type, OPT_TYPE_STRING_STR) && allowList ? OPT_TYPE_STRING_ID_STR : opt->type)));
|
||||
|
||||
if (!strEq(opt->type, OPT_TYPE_BOOLEAN_STR))
|
||||
{
|
||||
if (strEq(opt->type, OPT_TYPE_TIME_STR))
|
||||
{
|
||||
strLstAddIfMissing(
|
||||
ruleDataList, strNewFmt("%" PRId64, (int64_t)(cvtZToDouble(strZ(opt->defaultValue)) * 1000)));
|
||||
}
|
||||
else
|
||||
strLstAddIfMissing(ruleDataList, opt->defaultValue);
|
||||
|
||||
strLstAddIfMissing(
|
||||
ruleStrList,
|
||||
strNewFmt("%s%s%s", opt->defaultLiteral ? "" : "\"", strZ(opt->defaultValue), opt->defaultLiteral ? "" : "\""));
|
||||
}
|
||||
}
|
||||
|
||||
// Build command optional rules
|
||||
KeyValue *const optionalCmdRule = kvNew();
|
||||
|
||||
// Build optional data for commands
|
||||
for (unsigned int optCmdIdx = 0; optCmdIdx < lstSize(opt->cmdList); optCmdIdx++)
|
||||
{
|
||||
BldCfgOptionCommand *const optCmd = lstGet(opt->cmdList, optCmdIdx);
|
||||
String *const configCommand = strNew();
|
||||
KeyValue *const optionalCmdRuleType = kvNew();
|
||||
|
||||
bool multi = bldCfgRenderAllowList(configCommand, optCmd->allowList, true);
|
||||
multi = bldCfgRenderDepend(configCommand, optCmd->depend, true, multi);
|
||||
multi = bldCfgRenderDefault(configCommand, opt->type, optCmd->defaultValue, false, true, multi);
|
||||
// Depends
|
||||
if (optCmd->depend != NULL)
|
||||
kvAdd(optionalCmdRuleType, ruleDepend, VARSTR(bldCfgRenderValid(optCmd->depend)));
|
||||
|
||||
if (optCmd->required != opt->required)
|
||||
// Allow lists
|
||||
if (optCmd->allowList != NULL)
|
||||
{
|
||||
bldCfgRenderLf(configCommand, multi);
|
||||
kvAdd(
|
||||
optionalCmdRuleType, ruleAllowList,
|
||||
VARSTR(
|
||||
bldCfgRenderAllowList(
|
||||
optCmd->allowList, strEq(opt->type, OPT_TYPE_STRING_STR) ? OPT_TYPE_STRING_ID_STR : opt->type)));
|
||||
|
||||
strCatFmt(
|
||||
configCommand,
|
||||
" PARSE_RULE_OPTION_OPTIONAL_REQUIRED(%s),\n",
|
||||
cvtBoolToConstZ(optCmd->required));
|
||||
for (unsigned int allowIdx = 0; allowIdx < strLstSize(optCmd->allowList); allowIdx++)
|
||||
strLstAddIfMissing(ruleDataList, strLstGet(optCmd->allowList, allowIdx));
|
||||
}
|
||||
|
||||
if (!strEmpty(configCommand))
|
||||
// Defaults
|
||||
if (optCmd->defaultValue != NULL)
|
||||
{
|
||||
bldCfgRenderLf(configOptional, !strEmpty(configOptional));
|
||||
kvAdd(
|
||||
optionalCmdRuleType, ruleDefault,
|
||||
VARSTR(
|
||||
bldCfgRenderDefault(
|
||||
optCmd->defaultValue, opt->defaultLiteral,
|
||||
strEq(opt->type, OPT_TYPE_STRING_STR) && allowList ? OPT_TYPE_STRING_ID_STR : opt->type)));
|
||||
|
||||
strCatFmt(
|
||||
configOptional,
|
||||
" PARSE_RULE_OPTION_OPTIONAL_COMMAND_OVERRIDE\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_COMMAND(%s),\n"
|
||||
"\n"
|
||||
"%s"
|
||||
" )\n",
|
||||
strZ(bldEnum("cfgCmd", optCmd->name)), strZ(configCommand));
|
||||
if (!strEq(opt->type, OPT_TYPE_BOOLEAN_STR))
|
||||
{
|
||||
if (strEq(opt->type, OPT_TYPE_TIME_STR))
|
||||
{
|
||||
strLstAddIfMissing(
|
||||
ruleDataList, strNewFmt("%" PRId64, (int64_t)(cvtZToDouble(strZ(optCmd->defaultValue)) * 1000)));
|
||||
}
|
||||
else
|
||||
strLstAddIfMissing(ruleDataList, optCmd->defaultValue);
|
||||
|
||||
strLstAddIfMissing(
|
||||
ruleStrList,
|
||||
strNewFmt(
|
||||
"%s%s%s", opt->defaultLiteral ? "" : "\"", strZ(optCmd->defaultValue),
|
||||
opt->defaultLiteral ? "" : "\""));
|
||||
}
|
||||
}
|
||||
|
||||
// Requires
|
||||
if (optCmd->required != opt->required)
|
||||
{
|
||||
kvAdd(
|
||||
optionalCmdRuleType, ruleRequire,
|
||||
VARSTR(strNewFmt(" PARSE_RULE_OPTIONAL_%sREQUIRED()", optCmd->required ? "" : "NOT_")));
|
||||
}
|
||||
|
||||
// Add defaults
|
||||
if (varLstSize(kvKeyList(optionalCmdRuleType)) > 0)
|
||||
{
|
||||
for (unsigned int ruleIdx = 0; ruleIdx < sizeof(ruleList) / sizeof(Variant *); ruleIdx++)
|
||||
{
|
||||
if (kvKeyExists(optionalCmdRuleType, ruleList[ruleIdx]))
|
||||
kvAdd(optionalCmdRule, VARSTR(optCmd->name), kvGet(optionalCmdRuleType, ruleList[ruleIdx]));
|
||||
else if (kvKeyExists(optionalDefaultRule, ruleList[ruleIdx]))
|
||||
kvAdd(optionalCmdRule, VARSTR(optCmd->name), kvGet(optionalDefaultRule, ruleList[ruleIdx]));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add optional data
|
||||
if (!strEmpty(configOptional))
|
||||
// Add optional rules
|
||||
unsigned int optionalCmdRuleSize = varLstSize(kvKeyList(optionalCmdRule));
|
||||
unsigned int optionalDefaultRuleSize = varLstSize(kvKeyList(optionalDefaultRule));
|
||||
|
||||
if (optionalCmdRuleSize != 0 || optionalDefaultRuleSize != 0)
|
||||
{
|
||||
strCatFmt(
|
||||
strCatZ(
|
||||
config,
|
||||
"\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_LIST\n"
|
||||
" (\n"
|
||||
"%s"
|
||||
" ),\n",
|
||||
strZ(configOptional));
|
||||
" PARSE_RULE_OPTIONAL\n"
|
||||
" (\n");
|
||||
|
||||
if (optionalCmdRuleSize != 0)
|
||||
{
|
||||
KeyValue *const combine = kvNew();
|
||||
|
||||
for (unsigned int ruleIdx = 0; ruleIdx < optionalCmdRuleSize; ruleIdx++)
|
||||
{
|
||||
const Variant *const cmd = varLstGet(kvKeyList(optionalCmdRule), ruleIdx);
|
||||
const VariantList *const groupList = kvGetList(optionalCmdRule, cmd);
|
||||
String *const group = strNew();
|
||||
|
||||
for (unsigned int groupIdx = 0; groupIdx < varLstSize(groupList); groupIdx++)
|
||||
{
|
||||
strCatFmt(
|
||||
group,
|
||||
"\n"
|
||||
"%s,\n",
|
||||
strZ(varStr(varLstGet(groupList, groupIdx))));
|
||||
}
|
||||
|
||||
kvAdd(combine, VARSTR(group), cmd);
|
||||
}
|
||||
|
||||
unsigned int combineSize = varLstSize(kvKeyList(combine));
|
||||
|
||||
for (unsigned int ruleIdx = 0; ruleIdx < combineSize; ruleIdx++)
|
||||
{
|
||||
const Variant *const group = varLstGet(kvKeyList(combine), ruleIdx);
|
||||
const VariantList *const cmdList = kvGetList(combine, group);
|
||||
|
||||
if (ruleIdx != 0)
|
||||
strCatChr(config, '\n');
|
||||
|
||||
strCatZ(
|
||||
config,
|
||||
" PARSE_RULE_OPTIONAL_GROUP\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_FILTER_CMD\n"
|
||||
" (\n");
|
||||
|
||||
for (unsigned int cmdIdx = 0; cmdIdx < varLstSize(cmdList); cmdIdx++)
|
||||
{
|
||||
strCatFmt(
|
||||
config,
|
||||
" PARSE_RULE_VAL_CMD(%s),\n",
|
||||
strZ(bldEnum("cfgCmd", varStr(varLstGet(cmdList, cmdIdx)))));
|
||||
}
|
||||
|
||||
strCatFmt(
|
||||
config,
|
||||
" ),\n"
|
||||
"%s"
|
||||
" ),\n",
|
||||
strZ(varStr(group)));
|
||||
}
|
||||
}
|
||||
|
||||
if (optionalDefaultRuleSize != 0)
|
||||
{
|
||||
if (optionalCmdRuleSize != 0)
|
||||
strCatChr(config, '\n');
|
||||
|
||||
strCatZ(
|
||||
config,
|
||||
" PARSE_RULE_OPTIONAL_GROUP\n"
|
||||
" (\n");
|
||||
|
||||
for (unsigned int ruleIdx = 0; ruleIdx < optionalDefaultRuleSize; ruleIdx++)
|
||||
{
|
||||
const Variant *const key = varLstGet(kvKeyList(optionalDefaultRule), ruleIdx);
|
||||
|
||||
if (ruleIdx != 0)
|
||||
strCatChr(config, '\n');
|
||||
|
||||
strCatFmt(
|
||||
config,
|
||||
"%s,\n",
|
||||
strZ(varStr(kvGet(optionalDefaultRule, key))));
|
||||
}
|
||||
|
||||
strCatZ(config, " ),\n");
|
||||
}
|
||||
|
||||
strCatZ(config, " ),\n");
|
||||
}
|
||||
|
||||
strCatZ(config, " ),\n");
|
||||
|
||||
// Build rule values
|
||||
if (strEq(opt->type, OPT_TYPE_BOOLEAN_STR))
|
||||
continue;
|
||||
|
||||
StringList *ruleAddList = NULL;
|
||||
|
||||
if (strEq(opt->type, OPT_TYPE_STRING_STR) || strEq(opt->type, OPT_TYPE_PATH_STR))
|
||||
{
|
||||
if (allowList)
|
||||
ruleAddList = ruleStrIdList;
|
||||
else
|
||||
ruleAddList = ruleStrList;
|
||||
}
|
||||
else
|
||||
{
|
||||
ruleAddList = ruleIntList;
|
||||
ruleInt = true;
|
||||
}
|
||||
|
||||
for (unsigned int ruleDataIdx = 0; ruleDataIdx < strLstSize(ruleDataList); ruleDataIdx++)
|
||||
{
|
||||
if (ruleInt)
|
||||
strLstAddIfMissing(ruleAddList, strNewFmt("%20s", strZ(strLstGet(ruleDataList, ruleDataIdx))));
|
||||
else
|
||||
{
|
||||
if (allowList)
|
||||
strLstAddIfMissing(ruleAddList, strLstGet(ruleDataList, ruleDataIdx));
|
||||
else
|
||||
{
|
||||
strLstAddIfMissing(
|
||||
ruleAddList,
|
||||
strNewFmt(
|
||||
"%s%s%s", opt->defaultLiteral ? "" : "\"", strZ(strLstGet(ruleDataList, ruleDataIdx)),
|
||||
opt->defaultLiteral ? "" : "\""));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
strCatZ(
|
||||
@ -790,9 +1124,138 @@ bldCfgRenderParseAutoC(const Storage *const storageRepo, const BldCfg bldCfg)
|
||||
|
||||
strCatZ(config, "};\n");
|
||||
|
||||
|
||||
// Rule Strings
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
String *const configVal = strNew();
|
||||
|
||||
strLstSort(ruleStrList, sortOrderAsc);
|
||||
|
||||
strCatFmt(
|
||||
configVal,
|
||||
"\n"
|
||||
COMMENT_BLOCK_BEGIN "\n"
|
||||
"Rule Strings\n"
|
||||
COMMENT_BLOCK_END "\n");
|
||||
|
||||
strCatFmt(
|
||||
configVal, "%s\n",
|
||||
strZ(
|
||||
bldDefineRender(
|
||||
STRDEF("PARSE_RULE_VAL_STR(value)"),
|
||||
strNewFmt("PARSE_RULE_U32_%zu(value)", bldCfgRenderVar128Size(strLstSize(ruleStrList) - 1)))));
|
||||
|
||||
strCatFmt(
|
||||
configVal,
|
||||
"\n"
|
||||
"static const StringPub parseRuleValueStr[] =\n"
|
||||
"{\n");
|
||||
|
||||
for (unsigned int ruleStrIdx = 0; ruleStrIdx < strLstSize(ruleStrList); ruleStrIdx++)
|
||||
strCatFmt(configVal, " PARSE_RULE_STRPUB(%s),\n", strZ(strLstGet(ruleStrList, ruleStrIdx)));
|
||||
|
||||
strCatZ(configVal, "};\n");
|
||||
|
||||
strCatZ(
|
||||
configVal,
|
||||
"\n"
|
||||
"typedef enum\n"
|
||||
"{\n");
|
||||
|
||||
for (unsigned int ruleStrIdx = 0; ruleStrIdx < strLstSize(ruleStrList); ruleStrIdx++)
|
||||
{
|
||||
strCatFmt(
|
||||
configVal, " %s,\n",
|
||||
strZ(strNewFmt("parseRuleValStr%s", strZ(bldCfgRenderEnumStr(strLstGet(ruleStrList, ruleStrIdx))))));
|
||||
}
|
||||
|
||||
strCatZ(configVal, "} ParseRuleValueStr;\n");
|
||||
|
||||
// Rule StringIds
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
strLstSort(ruleStrIdList, sortOrderAsc);
|
||||
|
||||
strCatFmt(
|
||||
configVal,
|
||||
"\n"
|
||||
COMMENT_BLOCK_BEGIN "\n"
|
||||
"Rule StringIds\n"
|
||||
COMMENT_BLOCK_END "\n");
|
||||
|
||||
strCatFmt(
|
||||
configVal, "%s\n",
|
||||
strZ(
|
||||
bldDefineRender(
|
||||
STRDEF("PARSE_RULE_VAL_STRID(value)"),
|
||||
strNewFmt("PARSE_RULE_U32_%zu(value)", bldCfgRenderVar128Size(strLstSize(ruleStrIdList) - 1)))));
|
||||
|
||||
strCatFmt(
|
||||
configVal,
|
||||
"\n"
|
||||
"static const StringId parseRuleValueStrId[] =\n"
|
||||
"{\n");
|
||||
|
||||
for (unsigned int ruleStrIdIdx = 0; ruleStrIdIdx < strLstSize(ruleStrIdList); ruleStrIdIdx++)
|
||||
strCatFmt(configVal, " %s,\n", strZ(bldStrId(strZ(strLstGet(ruleStrIdList, ruleStrIdIdx)))));
|
||||
|
||||
strCatZ(configVal, "};\n");
|
||||
|
||||
strCatZ(
|
||||
configVal,
|
||||
"\n"
|
||||
"typedef enum\n"
|
||||
"{\n");
|
||||
|
||||
for (unsigned int ruleStrIdIdx = 0; ruleStrIdIdx < strLstSize(ruleStrIdList); ruleStrIdIdx++)
|
||||
strCatFmt(configVal, " %s,\n", strZ(bldEnum("parseRuleValStrId", strLstGet(ruleStrIdList, ruleStrIdIdx))));
|
||||
|
||||
strCatZ(configVal, "} ParseRuleValueStrId;\n");
|
||||
|
||||
// Rule Ints
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
strLstSort(ruleIntList, sortOrderAsc);
|
||||
|
||||
strCatFmt(
|
||||
configVal,
|
||||
"\n"
|
||||
COMMENT_BLOCK_BEGIN "\n"
|
||||
"Rule Ints\n"
|
||||
COMMENT_BLOCK_END "\n");
|
||||
|
||||
strCatFmt(
|
||||
configVal, "%s\n",
|
||||
strZ(
|
||||
bldDefineRender(
|
||||
STRDEF("PARSE_RULE_VAL_INT(value)"),
|
||||
strNewFmt("PARSE_RULE_U32_%zu(value)", bldCfgRenderVar128Size(strLstSize(ruleIntList) - 1)))));
|
||||
|
||||
strCatFmt(
|
||||
configVal,
|
||||
"\n"
|
||||
"static const int64_t parseRuleValueInt[] =\n"
|
||||
"{\n");
|
||||
|
||||
for (unsigned int ruleIntIdx = 0; ruleIntIdx < strLstSize(ruleIntList); ruleIntIdx++)
|
||||
strCatFmt(configVal, " %s,\n", strZ(strTrim(strLstGet(ruleIntList, ruleIntIdx))));
|
||||
|
||||
strCatZ(configVal, "};\n");
|
||||
|
||||
strCatZ(
|
||||
configVal,
|
||||
"\n"
|
||||
"typedef enum\n"
|
||||
"{\n");
|
||||
|
||||
for (unsigned int ruleIntIdx = 0; ruleIntIdx < strLstSize(ruleIntList); ruleIntIdx++)
|
||||
strCatFmt(configVal, " %s,\n", strZ(bldEnum("parseRuleValInt", strLstGet(ruleIntList, ruleIntIdx))));
|
||||
|
||||
strCatZ(configVal, "} ParseRuleValueInt;\n");
|
||||
|
||||
// Write to storage
|
||||
// -----------------------------------------------------------------------------------------------------------------------------
|
||||
bldPut(storageRepo, "src/config/parse.auto.c", BUFSTR(config));
|
||||
bldPut(
|
||||
storageRepo, "src/config/parse.auto.c",
|
||||
BUFSTR(strNewFmt("%s%s%s", strZ(bldHeader(CONFIG_MODULE, PARSE_AUTO_COMMENT)), strZ(configVal), strZ(config))));
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
|
@ -449,7 +449,7 @@ helpRender(const Buffer *const helpData)
|
||||
strFirstLower(summary);
|
||||
|
||||
// Output current and default values if they exist
|
||||
const String *defaultValue = helpRenderValue(cfgOptionDefault(optionId), cfgParseOptionType(optionId));
|
||||
const String *defaultValue = cfgOptionDefault(optionId);
|
||||
const String *value = NULL;
|
||||
|
||||
if (cfgOptionIdxSource(optionId, 0) != cfgSourceDefault)
|
||||
@ -516,7 +516,7 @@ helpRender(const Buffer *const helpData)
|
||||
helpRenderText(optionData[option.id].description, optionData[option.id].internal, 0, true, CONSOLE_WIDTH)));
|
||||
|
||||
// Output current and default values if they exist
|
||||
const String *defaultValue = helpRenderValue(cfgOptionDefault(option.id), cfgParseOptionType(option.id));
|
||||
const String *defaultValue = cfgOptionDefault(option.id);
|
||||
const String *value = NULL;
|
||||
|
||||
if (cfgOptionIdxSource(option.id, 0) != cfgSourceDefault)
|
||||
|
@ -377,41 +377,7 @@ cfgOptionIdxTotal(ConfigOption optionId)
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
static Variant *
|
||||
cfgOptionDefaultValue(ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
Variant *result;
|
||||
Variant *defaultValue = varNewStrZ(cfgParseOptionDefault(cfgCommand(), optionId));
|
||||
|
||||
switch (cfgParseOptionType(optionId))
|
||||
{
|
||||
case cfgOptTypeBoolean:
|
||||
result = varNewBool(varBoolForce(defaultValue));
|
||||
break;
|
||||
|
||||
case cfgOptTypeInteger:
|
||||
case cfgOptTypeSize:
|
||||
case cfgOptTypeTime:
|
||||
result = varNewInt64(varInt64Force(defaultValue));
|
||||
break;
|
||||
|
||||
case cfgOptTypePath:
|
||||
case cfgOptTypeString:
|
||||
result = varDup(defaultValue);
|
||||
break;
|
||||
|
||||
default:
|
||||
THROW_FMT(AssertError, "default value not available for option type %u", cfgParseOptionType(optionId));
|
||||
}
|
||||
|
||||
FUNCTION_TEST_RETURN(result);
|
||||
}
|
||||
|
||||
const Variant *
|
||||
const String *
|
||||
cfgOptionDefault(ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
@ -422,16 +388,7 @@ cfgOptionDefault(ConfigOption optionId)
|
||||
ASSERT(optionId < CFG_OPTION_TOTAL);
|
||||
|
||||
if (configLocal->option[optionId].defaultValue == NULL)
|
||||
{
|
||||
if (cfgParseOptionDefault(cfgCommand(), optionId) != NULL)
|
||||
{
|
||||
MEM_CONTEXT_BEGIN(configLocal->memContext)
|
||||
{
|
||||
configLocal->option[optionId].defaultValue = cfgOptionDefaultValue(optionId);
|
||||
}
|
||||
MEM_CONTEXT_END();
|
||||
}
|
||||
}
|
||||
configLocal->option[optionId].defaultValue = cfgParseOptionDefault(cfgCommand(), optionId);
|
||||
|
||||
FUNCTION_TEST_RETURN(configLocal->option[optionId].defaultValue);
|
||||
}
|
||||
@ -450,15 +407,18 @@ cfgOptionDefaultSet(ConfigOption optionId, const Variant *defaultValue)
|
||||
|
||||
MEM_CONTEXT_BEGIN(configLocal->memContext)
|
||||
{
|
||||
// Duplicate into this context
|
||||
defaultValue = varDup(defaultValue);
|
||||
|
||||
// Set the default value
|
||||
configLocal->option[optionId].defaultValue = varDup(defaultValue);
|
||||
configLocal->option[optionId].defaultValue = varStr(defaultValue);
|
||||
|
||||
// Copy the value to option indexes that are marked as default so the default can be retrieved quickly
|
||||
for (unsigned int optionIdx = 0; optionIdx < cfgOptionIdxTotal(optionId); optionIdx++)
|
||||
{
|
||||
if (configLocal->option[optionId].index[optionIdx].source == cfgSourceDefault)
|
||||
{
|
||||
configLocal->option[optionId].index[optionIdx].value = configLocal->option[optionId].defaultValue;
|
||||
configLocal->option[optionId].index[optionIdx].value = defaultValue;
|
||||
configLocal->option[optionId].index[optionIdx].display = NULL;
|
||||
}
|
||||
}
|
||||
|
@ -170,9 +170,6 @@ void cfgCommandSet(ConfigCommand commandId, ConfigCommandRole commandRoleId);
|
||||
// pgBackRest exe
|
||||
const String *cfgExe(void);
|
||||
|
||||
// Option default - should only be called by the help command
|
||||
const Variant *cfgOptionDefault(ConfigOption optionId);
|
||||
|
||||
// Set option default. Option defaults are generally not set in advance because the vast majority of them are never used. It is
|
||||
// more efficient to generate them when they are requested. Some defaults are (e.g. the exe path) are set at runtime.
|
||||
void cfgOptionDefaultSet(ConfigOption optionId, const Variant *defaultValue);
|
||||
|
@ -65,7 +65,7 @@ typedef struct Config
|
||||
bool valid; // Is option valid for current command?
|
||||
bool group; // In a group?
|
||||
unsigned int groupId; // Id if in a group
|
||||
const Variant *defaultValue; // Default value
|
||||
const String *defaultValue; // Default value
|
||||
ConfigOptionValue *index; // List of indexed values (only 1 unless the option is indexed)
|
||||
} option[CFG_OPTION_TOTAL];
|
||||
} Config;
|
||||
@ -94,6 +94,9 @@ unsigned int cfgOptionGroupId(ConfigOption optionId);
|
||||
/***********************************************************************************************************************************
|
||||
Option Functions
|
||||
***********************************************************************************************************************************/
|
||||
// Option default - should only be called by the help command
|
||||
const String *cfgOptionDefault(ConfigOption optionId);
|
||||
|
||||
// Format a variant for display using the supplied option type. cfgOptionDisplay()/cfgOptionIdxDisplay() should be used whenever
|
||||
// possible, but sometimes the variant needs to be manipulated before being formatted.
|
||||
const String *cfgOptionDisplayVar(const Variant *const value, const ConfigOptionType optionType);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -50,12 +50,6 @@ Prefix for environment variables
|
||||
// In some environments this will not be extern'd
|
||||
extern char **environ;
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Option value constants
|
||||
***********************************************************************************************************************************/
|
||||
VARIANT_STRDEF_STATIC(OPTION_VALUE_0, ZERO_Z);
|
||||
VARIANT_STRDEF_STATIC(OPTION_VALUE_1, ONE_Z);
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Define how a command is parsed
|
||||
***********************************************************************************************************************************/
|
||||
@ -133,24 +127,29 @@ typedef struct ParseRuleOption
|
||||
bool group:1; // In a group?
|
||||
unsigned int groupId:1; // Id if in a group
|
||||
bool deprecateMatch:1; // Does a deprecated name exactly match the option name?
|
||||
unsigned int packSize:7; // Size of optional data in pack format
|
||||
uint32_t commandRoleValid[CFG_COMMAND_ROLE_TOTAL]; // Valid for the command role?
|
||||
|
||||
const void **data; // Optional data and command overrides
|
||||
const unsigned char *pack; // Optional data in pack format
|
||||
} ParseRuleOption;
|
||||
|
||||
// Define additional types of data that can be associated with an option. Because these types are rare they are not given dedicated
|
||||
// fields and are instead packed into an array which is read at runtime. This may seem inefficient but they are only accessed a
|
||||
// single time during parse so space efficiency is more important than performance.
|
||||
// fields and are instead packed and read at runtime. This may seem inefficient but they are only accessed a single time during
|
||||
// parse so space efficiency is more important than performance.
|
||||
typedef enum
|
||||
{
|
||||
parseRuleOptionDataTypeEnd, // Indicates there is no more data
|
||||
parseRuleOptionDataTypeAllowList,
|
||||
parseRuleOptionDataTypeAllowRange,
|
||||
parseRuleOptionDataTypeCommand,
|
||||
parseRuleOptionDataTypeDefault,
|
||||
parseRuleOptionDataTypeDepend,
|
||||
parseRuleOptionDataTypeRequired,
|
||||
} ParseRuleOptionDataType;
|
||||
parseRuleOptionalTypeValid = 1,
|
||||
parseRuleOptionalTypeAllowRange,
|
||||
parseRuleOptionalTypeAllowList,
|
||||
parseRuleOptionalTypeDefault,
|
||||
parseRuleOptionalTypeRequired,
|
||||
} ParseRuleOptionalType;
|
||||
|
||||
// Optional rule filter types
|
||||
typedef enum
|
||||
{
|
||||
parseRuleFilterTypeCommand = 1,
|
||||
} ParseRuleFilterType;
|
||||
|
||||
// Macros used to define parse rules in parse.auto.c in a format that diffs well
|
||||
#define PARSE_RULE_OPTION(...) \
|
||||
@ -204,45 +203,46 @@ typedef enum
|
||||
#define PARSE_RULE_OPTION_COMMAND(commandParam) \
|
||||
| (1 << commandParam)
|
||||
|
||||
#define PARSE_RULE_OPTION_OPTIONAL_PUSH_LIST(type, size, data, ...) \
|
||||
(const void *)((uint32_t)type << 24 | (uint32_t)size << 16 | (uint32_t)data), __VA_ARGS__
|
||||
#define PARSE_RULE_STRPUB(value) {.buffer = (char *)value, .size = sizeof(value) - 1}
|
||||
|
||||
#define PARSE_RULE_OPTION_OPTIONAL_LIST(...) \
|
||||
.data = (const void *[]){__VA_ARGS__ NULL}
|
||||
// Macros used to define optional parse rules in pack format
|
||||
#define PARSE_RULE_VARINT_01(value) \
|
||||
value
|
||||
#define PARSE_RULE_VARINT_02(value) \
|
||||
0x80 | (value & 0x7f), (value >> 7) & 0x7f
|
||||
|
||||
#define PARSE_RULE_OPTION_OPTIONAL_PUSH(type, size, data) \
|
||||
(const void *)((uint32_t)type << 24 | (uint32_t)size << 16 | (uint32_t)data)
|
||||
#define PARSE_RULE_BOOL_TRUE 0x28
|
||||
#define PARSE_RULE_BOOL_FALSE 0x20
|
||||
#define PARSE_RULE_U32_1(value) 0x88, PARSE_RULE_VARINT_01(value)
|
||||
#define PARSE_RULE_U32_2(value) 0x88, PARSE_RULE_VARINT_02(value)
|
||||
|
||||
#define PARSE_RULE_OPTION_OPTIONAL_COMMAND_OVERRIDE(...) \
|
||||
__VA_ARGS__
|
||||
#define PARSE_RULE_PACK(...) __VA_ARGS__ 0x00
|
||||
#define PARSE_RULE_PACK_SIZE(...) \
|
||||
0xf0, 0x02, sizeof((const unsigned char []){PARSE_RULE_PACK(__VA_ARGS__)}), \
|
||||
PARSE_RULE_PACK(__VA_ARGS__)
|
||||
|
||||
#define PARSE_RULE_OPTION_OPTIONAL_COMMAND(command) \
|
||||
PARSE_RULE_OPTION_OPTIONAL_PUSH(parseRuleOptionDataTypeCommand, 0, command)
|
||||
#define PARSE_RULE_VAL_BOOL_TRUE PARSE_RULE_BOOL_TRUE
|
||||
#define PARSE_RULE_VAL_BOOL_FALSE PARSE_RULE_BOOL_FALSE
|
||||
|
||||
#define PARSE_RULE_OPTION_OPTIONAL_ALLOW_LIST(...) \
|
||||
PARSE_RULE_OPTION_OPTIONAL_PUSH_LIST( \
|
||||
parseRuleOptionDataTypeAllowList, sizeof((const char *[]){__VA_ARGS__}) / sizeof(const char *), 0, __VA_ARGS__)
|
||||
#define PARSE_RULE_OPTIONAL(...) \
|
||||
.packSize = sizeof((const unsigned char []){PARSE_RULE_PACK(__VA_ARGS__)}), \
|
||||
.pack = (const unsigned char []){PARSE_RULE_PACK(__VA_ARGS__)}
|
||||
#define PARSE_RULE_OPTIONAL_GROUP(...) PARSE_RULE_PACK_SIZE(__VA_ARGS__)
|
||||
|
||||
#define PARSE_RULE_OPTION_OPTIONAL_ALLOW_RANGE(rangeMinParam, rangeMaxParam) \
|
||||
PARSE_RULE_OPTION_OPTIONAL_PUSH_LIST( \
|
||||
parseRuleOptionDataTypeAllowRange, 4, 0, \
|
||||
(const void *)(intptr_t)(int32_t)((int64_t)rangeMinParam >> 32), \
|
||||
(const void *)(intptr_t)(int32_t)((int64_t)rangeMinParam & 0xFFFFFFFF), \
|
||||
(const void *)(intptr_t)(int32_t)((int64_t)rangeMaxParam >> 32), \
|
||||
(const void *)(intptr_t)(int32_t)((int64_t)rangeMaxParam & 0xFFFFFFFF))
|
||||
#define PARSE_RULE_FILTER_CMD(...) \
|
||||
PARSE_RULE_PACK_SIZE(PARSE_RULE_U32_1(parseRuleFilterTypeCommand), __VA_ARGS__)
|
||||
|
||||
#define PARSE_RULE_OPTION_OPTIONAL_DEFAULT(defaultParam) \
|
||||
PARSE_RULE_OPTION_OPTIONAL_PUSH_LIST(parseRuleOptionDataTypeDefault, 1, 0, defaultParam)
|
||||
|
||||
#define PARSE_RULE_OPTION_OPTIONAL_DEPEND(optionDepend) \
|
||||
PARSE_RULE_OPTION_OPTIONAL_PUSH(parseRuleOptionDataTypeDepend, 0, optionDepend)
|
||||
|
||||
#define PARSE_RULE_OPTION_OPTIONAL_DEPEND_LIST(optionDepend, ...) \
|
||||
PARSE_RULE_OPTION_OPTIONAL_PUSH_LIST( \
|
||||
parseRuleOptionDataTypeDepend, sizeof((const char *[]){__VA_ARGS__}) / sizeof(const char *), optionDepend, __VA_ARGS__)
|
||||
|
||||
#define PARSE_RULE_OPTION_OPTIONAL_REQUIRED(requiredParam) \
|
||||
PARSE_RULE_OPTION_OPTIONAL_PUSH(parseRuleOptionDataTypeRequired, 0, requiredParam)
|
||||
#define PARSE_RULE_OPTIONAL_DEPEND(...) \
|
||||
PARSE_RULE_U32_1(parseRuleOptionalTypeValid), PARSE_RULE_PACK_SIZE(__VA_ARGS__)
|
||||
#define PARSE_RULE_OPTIONAL_ALLOW_LIST(...) \
|
||||
PARSE_RULE_U32_1(parseRuleOptionalTypeAllowList), PARSE_RULE_PACK_SIZE(__VA_ARGS__)
|
||||
#define PARSE_RULE_OPTIONAL_ALLOW_RANGE(...) \
|
||||
PARSE_RULE_U32_1(parseRuleOptionalTypeAllowRange), PARSE_RULE_PACK_SIZE(__VA_ARGS__)
|
||||
#define PARSE_RULE_OPTIONAL_DEFAULT(...) \
|
||||
PARSE_RULE_U32_1(parseRuleOptionalTypeDefault), PARSE_RULE_PACK_SIZE(__VA_ARGS__)
|
||||
#define PARSE_RULE_OPTIONAL_REQUIRED(...) \
|
||||
PARSE_RULE_U32_1(parseRuleOptionalTypeRequired), PARSE_RULE_PACK_SIZE(__VA_ARGS__)
|
||||
#define PARSE_RULE_OPTIONAL_NOT_REQUIRED(...) PARSE_RULE_OPTIONAL_REQUIRED(__VA_ARGS__)
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Define option deprecations
|
||||
@ -260,84 +260,6 @@ Include automatically generated parse data
|
||||
***********************************************************************************************************************************/
|
||||
#include "config/parse.auto.c"
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Find optional data for a command and option
|
||||
***********************************************************************************************************************************/
|
||||
// Extract an int64 from optional data list
|
||||
#define PARSE_RULE_DATA_INT64(data, index) \
|
||||
((int64_t)(intptr_t)data.list[index] << 32 | (int64_t)(intptr_t)data.list[index + 1])
|
||||
|
||||
// Extracted option data
|
||||
typedef struct ParseRuleOptionData
|
||||
{
|
||||
bool found; // Was the data found?
|
||||
int data; // Data value
|
||||
unsigned int listSize; // Data list size
|
||||
const void **list; // Data list
|
||||
} ParseRuleOptionData;
|
||||
|
||||
static ParseRuleOptionData
|
||||
parseRuleOptionDataFind(ParseRuleOptionDataType typeFind, ConfigCommand commandId, ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, typeFind);
|
||||
FUNCTION_TEST_PARAM(ENUM, commandId);
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ParseRuleOptionData result = {0};
|
||||
|
||||
const void **dataList = parseRuleOption[optionId].data;
|
||||
|
||||
// Only proceed if there is data
|
||||
if (dataList != NULL)
|
||||
{
|
||||
ParseRuleOptionDataType type;
|
||||
unsigned int offset = 0;
|
||||
unsigned int size;
|
||||
int data;
|
||||
unsigned int commandCurrent = UINT_MAX;
|
||||
|
||||
// Loop through all data
|
||||
do
|
||||
{
|
||||
// Extract data
|
||||
type = (ParseRuleOptionDataType)(((uintptr_t)dataList[offset] >> 24) & 0xFF);
|
||||
size = ((uintptr_t)dataList[offset] >> 16) & 0xFF;
|
||||
data = (uintptr_t)dataList[offset] & 0xFFFF;
|
||||
|
||||
// If a command block then set the current command
|
||||
if (type == parseRuleOptionDataTypeCommand)
|
||||
{
|
||||
// If data was not found in the expected command then there's nothing more to look for
|
||||
if (commandCurrent == commandId)
|
||||
break;
|
||||
|
||||
// Set the current command
|
||||
commandCurrent = (unsigned int)data;
|
||||
}
|
||||
// Only find type if not in a command block yet or in the expected command
|
||||
else if (type == typeFind && (commandCurrent == UINT_MAX || commandCurrent == commandId))
|
||||
{
|
||||
// Store the data found
|
||||
result.found = true;
|
||||
result.data = data;
|
||||
result.listSize = size;
|
||||
result.list = &dataList[offset + 1];
|
||||
|
||||
// If found in the expected command block then nothing more to look for
|
||||
if (commandCurrent == commandId)
|
||||
break;
|
||||
}
|
||||
|
||||
offset += size + 1;
|
||||
}
|
||||
while (type != parseRuleOptionDataTypeEnd);
|
||||
}
|
||||
|
||||
FUNCTION_TEST_RETURN(result);
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Struct to hold options parsed from the command line
|
||||
***********************************************************************************************************************************/
|
||||
@ -739,8 +661,356 @@ cfgParseOption(const String *const optionCandidate, const CfgParseOptionParam pa
|
||||
FUNCTION_TEST_RETURN((CfgParseOptionResult){0});
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Get the underlying data type for an option
|
||||
***********************************************************************************************************************************/
|
||||
typedef enum
|
||||
{
|
||||
cfgOptDataTypeBoolean, // Boolean
|
||||
cfgOptDataTypeInteger, // Signed 64-bit integer
|
||||
cfgOptDataTypeString, // String
|
||||
} ConfigOptionDataType;
|
||||
|
||||
static ConfigOptionDataType
|
||||
cfgParseOptionDataType(ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(optionId < CFG_OPTION_TOTAL);
|
||||
|
||||
switch (parseRuleOption[optionId].type)
|
||||
{
|
||||
case cfgOptTypeBoolean:
|
||||
FUNCTION_TEST_RETURN(cfgOptDataTypeBoolean);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ASSERT(
|
||||
parseRuleOption[optionId].type == cfgOptTypeHash || parseRuleOption[optionId].type == cfgOptTypeList ||
|
||||
parseRuleOption[optionId].type == cfgOptTypePath || parseRuleOption[optionId].type == cfgOptTypeString);
|
||||
|
||||
FUNCTION_TEST_RETURN(cfgOptDataTypeString);
|
||||
}
|
||||
|
||||
/***********************************************************************************************************************************
|
||||
Find an optional rule
|
||||
***********************************************************************************************************************************/
|
||||
typedef struct CfgParseOptionalRuleState
|
||||
{
|
||||
PackRead *pack;
|
||||
unsigned int typeNext;
|
||||
bool done;
|
||||
|
||||
// Valid
|
||||
const unsigned char *valid;
|
||||
size_t validSize;
|
||||
|
||||
// Allow range
|
||||
int64_t allowRangeMin;
|
||||
int64_t allowRangeMax;
|
||||
|
||||
// Allow list
|
||||
const unsigned char *allowList;
|
||||
size_t allowListSize;
|
||||
|
||||
// Default
|
||||
const Variant *defaultValue;
|
||||
const String *defaultRaw;
|
||||
|
||||
// Required
|
||||
bool required;
|
||||
} CfgParseOptionalRuleState;
|
||||
|
||||
static bool
|
||||
cfgParseOptionalFilterDepend(PackRead *const filter, const Config *const config, const unsigned int optionListIdx)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM(PACK_READ, filter);
|
||||
FUNCTION_TEST_PARAM_P(VOID, config);
|
||||
FUNCTION_TEST_PARAM(UINT, optionListIdx);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
// Get the depend option value
|
||||
const ConfigOption dependId = (ConfigOption)pckReadU32P(filter);
|
||||
ASSERT(config->option[dependId].index != NULL);
|
||||
const Variant *const dependValue = config->option[dependId].index[optionListIdx].value;
|
||||
|
||||
// Is the dependency resolved?
|
||||
bool result = false;
|
||||
|
||||
if (dependValue != NULL)
|
||||
{
|
||||
// If a depend list exists, make sure the value is in the list
|
||||
if (pckReadNext(filter))
|
||||
{
|
||||
StringId dependValueStrId = 0;
|
||||
|
||||
if (cfgParseOptionDataType(dependId) == cfgOptDataTypeString)
|
||||
{
|
||||
TRY_BEGIN()
|
||||
{
|
||||
dependValueStrId = strIdFromStr(stringIdBit5, varStr(dependValue));
|
||||
}
|
||||
CATCH_ANY()
|
||||
{
|
||||
dependValueStrId = strIdFromStr(stringIdBit6, varStr(dependValue));
|
||||
}
|
||||
TRY_END();
|
||||
}
|
||||
|
||||
do
|
||||
{
|
||||
switch (cfgParseOptionDataType(dependId))
|
||||
{
|
||||
case cfgOptDataTypeBoolean:
|
||||
result = pckReadBoolP(filter) == varBool(dependValue);
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
ASSERT(cfgParseOptionDataType(dependId) == cfgOptDataTypeString);
|
||||
|
||||
if (parseRuleValueStrId[pckReadU32P(filter)] == dependValueStrId)
|
||||
result = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
while (pckReadNext(filter));
|
||||
}
|
||||
else
|
||||
result = true;
|
||||
}
|
||||
|
||||
FUNCTION_TEST_RETURN(result);
|
||||
}
|
||||
|
||||
static bool
|
||||
cfgParseOptionalRule(
|
||||
CfgParseOptionalRuleState *optionalRules, ParseRuleOptionalType optionalRuleType, ConfigCommand commandId,
|
||||
const ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
FUNCTION_TEST_PARAM_P(VOID, optionalRules);
|
||||
FUNCTION_TEST_PARAM(ENUM, optionalRuleType);
|
||||
FUNCTION_TEST_PARAM(ENUM, commandId);
|
||||
FUNCTION_TEST_PARAM(ENUM, optionId);
|
||||
FUNCTION_TEST_END();
|
||||
|
||||
ASSERT(optionalRuleType != 0);
|
||||
ASSERT(commandId < CFG_COMMAND_TOTAL);
|
||||
ASSERT(optionId < CFG_OPTION_TOTAL);
|
||||
|
||||
bool result = false;
|
||||
|
||||
// Check for optional rules
|
||||
if (!optionalRules->done && parseRuleOption[optionId].pack != NULL)
|
||||
{
|
||||
// Initialize optional rules
|
||||
if (optionalRules->pack == NULL)
|
||||
{
|
||||
PackRead *const groupList = pckReadNewC(parseRuleOption[optionId].pack, parseRuleOption[optionId].packSize);
|
||||
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
// Seach for a matching group
|
||||
do
|
||||
{
|
||||
// Get the group pack
|
||||
PackRead *group = pckReadPackReadConstP(groupList);
|
||||
|
||||
// Process filters if any
|
||||
pckReadNext(group);
|
||||
|
||||
if (pckReadType(group) == pckTypePack)
|
||||
{
|
||||
// Check for filter match
|
||||
bool match = false;
|
||||
PackRead *const filter = pckReadPackReadConstP(group);
|
||||
const ParseRuleFilterType filterType = (ParseRuleFilterType)pckReadU32P(filter);
|
||||
|
||||
switch (filterType)
|
||||
{
|
||||
default:
|
||||
{
|
||||
ASSERT(filterType == parseRuleFilterTypeCommand);
|
||||
|
||||
while (pckReadNext(filter))
|
||||
{
|
||||
if ((ConfigCommand)pckReadU32P(filter) == commandId)
|
||||
{
|
||||
match = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Filter did not match
|
||||
if (!match)
|
||||
group = NULL;
|
||||
}
|
||||
|
||||
// If the group matched
|
||||
if (group != NULL)
|
||||
{
|
||||
// Get first optional rule type. This is needed since pckReadNext() has already been called and it cannot
|
||||
// be called again until data is read.
|
||||
optionalRules->typeNext = pckReadU32P(group);
|
||||
ASSERT(optionalRules->typeNext != 0);
|
||||
|
||||
// Move group to prior context and stop searching
|
||||
optionalRules->pack = pckReadMove(group, memContextPrior());
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (pckReadNext(groupList));
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
|
||||
// If no group matched then done
|
||||
if (optionalRules->pack == NULL)
|
||||
{
|
||||
optionalRules->done = true;
|
||||
FUNCTION_TEST_RETURN(false);
|
||||
}
|
||||
}
|
||||
|
||||
// Search for the specified optional rule
|
||||
do
|
||||
{
|
||||
// Read the next optional rule type if it has not already been read
|
||||
if (optionalRules->typeNext == 0)
|
||||
{
|
||||
// If there are no more rules then done
|
||||
if (!pckReadNext(optionalRules->pack))
|
||||
{
|
||||
optionalRules->done = true;
|
||||
FUNCTION_TEST_RETURN(false);
|
||||
}
|
||||
|
||||
optionalRules->typeNext = pckReadU32P(optionalRules->pack);
|
||||
ASSERT(optionalRules->typeNext != 0);
|
||||
}
|
||||
|
||||
// If this is the requested optional rule
|
||||
if (optionalRules->typeNext == optionalRuleType)
|
||||
{
|
||||
// Optional rule was found
|
||||
result = true;
|
||||
|
||||
// Process optional rule
|
||||
switch (optionalRuleType)
|
||||
{
|
||||
case parseRuleOptionalTypeValid:
|
||||
{
|
||||
pckReadNext(optionalRules->pack);
|
||||
|
||||
optionalRules->valid = pckReadBufPtr(optionalRules->pack);
|
||||
optionalRules->validSize = pckReadSize(optionalRules->pack);
|
||||
|
||||
pckReadConsume(optionalRules->pack);
|
||||
break;
|
||||
}
|
||||
|
||||
case parseRuleOptionalTypeAllowList:
|
||||
{
|
||||
pckReadNext(optionalRules->pack);
|
||||
|
||||
optionalRules->allowList = pckReadBufPtr(optionalRules->pack);
|
||||
optionalRules->allowListSize = pckReadSize(optionalRules->pack);
|
||||
|
||||
pckReadConsume(optionalRules->pack);
|
||||
break;
|
||||
}
|
||||
|
||||
case parseRuleOptionalTypeAllowRange:
|
||||
{
|
||||
PackRead *const ruleData = pckReadPackReadConstP(optionalRules->pack);
|
||||
|
||||
optionalRules->allowRangeMin = parseRuleValueInt[pckReadU32P(ruleData)];
|
||||
optionalRules->allowRangeMax = parseRuleValueInt[pckReadU32P(ruleData)];
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case parseRuleOptionalTypeDefault:
|
||||
{
|
||||
PackRead *const ruleData = pckReadPackReadConstP(optionalRules->pack);
|
||||
pckReadNext(ruleData);
|
||||
|
||||
switch (pckReadType(ruleData))
|
||||
{
|
||||
case pckTypeBool:
|
||||
optionalRules->defaultValue = pckReadBoolP(ruleData) ? BOOL_TRUE_VAR : BOOL_FALSE_VAR;
|
||||
optionalRules->defaultRaw = varBool(optionalRules->defaultValue) ? Y_STR : N_STR;
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
switch (parseRuleOption[optionId].type)
|
||||
{
|
||||
case cfgOptTypeInteger:
|
||||
case cfgOptTypeTime:
|
||||
case cfgOptTypeSize:
|
||||
{
|
||||
optionalRules->defaultValue = varNewInt64(parseRuleValueInt[pckReadU32P(ruleData)]);
|
||||
optionalRules->defaultRaw = (const String *)&parseRuleValueStr[pckReadU32P(ruleData)];
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case cfgOptTypePath:
|
||||
case cfgOptTypeString:
|
||||
{
|
||||
optionalRules->defaultRaw = (const String *)&parseRuleValueStr[pckReadU32P(ruleData)];
|
||||
optionalRules->defaultValue = varNewStr(optionalRules->defaultRaw);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
ASSERT(optionalRuleType == parseRuleOptionalTypeRequired);
|
||||
|
||||
optionalRules->required = !parseRuleOption[optionId].required;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Else not the requested optional rule
|
||||
else
|
||||
{
|
||||
// If the optional rule type is greater than requested then return. The optional rule may be requested later.
|
||||
if (optionalRules->typeNext > optionalRuleType)
|
||||
FUNCTION_TEST_RETURN(false);
|
||||
|
||||
// Consume the unused optional rule
|
||||
pckReadConsume(optionalRules->pack);
|
||||
}
|
||||
|
||||
// Type will need to be read again on next iteration
|
||||
optionalRules->typeNext = 0;
|
||||
}
|
||||
while (!result);
|
||||
}
|
||||
|
||||
FUNCTION_TEST_RETURN(result);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
const char *
|
||||
const String *
|
||||
cfgParseOptionDefault(ConfigCommand commandId, ConfigOption optionId)
|
||||
{
|
||||
FUNCTION_TEST_BEGIN();
|
||||
@ -751,12 +1021,18 @@ cfgParseOptionDefault(ConfigCommand commandId, ConfigOption optionId)
|
||||
ASSERT(commandId < CFG_COMMAND_TOTAL);
|
||||
ASSERT(optionId < CFG_OPTION_TOTAL);
|
||||
|
||||
ParseRuleOptionData data = parseRuleOptionDataFind(parseRuleOptionDataTypeDefault, commandId, optionId);
|
||||
const String *result = NULL;
|
||||
|
||||
if (data.found)
|
||||
FUNCTION_TEST_RETURN((const char *)data.list[0]);
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
CfgParseOptionalRuleState optionalRules = {0};
|
||||
|
||||
FUNCTION_TEST_RETURN(NULL);
|
||||
if (cfgParseOptionalRule(&optionalRules, parseRuleOptionalTypeDefault, commandId, optionId))
|
||||
result = optionalRules.defaultRaw;
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
|
||||
FUNCTION_TEST_RETURN(result);
|
||||
}
|
||||
|
||||
/**********************************************************************************************************************************/
|
||||
@ -810,10 +1086,23 @@ cfgParseOptionRequired(ConfigCommand commandId, ConfigOption optionId)
|
||||
ASSERT(commandId < CFG_COMMAND_TOTAL);
|
||||
ASSERT(optionId < CFG_OPTION_TOTAL);
|
||||
|
||||
ParseRuleOptionData data = parseRuleOptionDataFind(parseRuleOptionDataTypeRequired, commandId, optionId);
|
||||
bool found = false;
|
||||
bool result = false;
|
||||
|
||||
if (data.found)
|
||||
FUNCTION_TEST_RETURN((bool)data.data);
|
||||
MEM_CONTEXT_TEMP_BEGIN()
|
||||
{
|
||||
CfgParseOptionalRuleState optionalRules = {0};
|
||||
|
||||
if (cfgParseOptionalRule(&optionalRules, parseRuleOptionalTypeRequired, commandId, optionId))
|
||||
{
|
||||
found = true;
|
||||
result = optionalRules.required;
|
||||
}
|
||||
}
|
||||
MEM_CONTEXT_TEMP_END();
|
||||
|
||||
if (found)
|
||||
FUNCTION_TEST_RETURN(result);
|
||||
|
||||
FUNCTION_TEST_RETURN(parseRuleOption[optionId].required);
|
||||
}
|
||||
@ -1503,8 +1792,10 @@ configParse(const Storage *storage, unsigned int argListSize, const char *argLis
|
||||
// ---------------------------------------------------------------------------------------------------------------------
|
||||
// Load the configuration file(s)
|
||||
String *configString = cfgFileLoad(
|
||||
storage, parseOptionList, STR(cfgParseOptionDefault(config->command, cfgOptConfig)),
|
||||
STR(cfgParseOptionDefault(config->command, cfgOptConfigIncludePath)), PGBACKREST_CONFIG_ORIG_PATH_FILE_STR);
|
||||
storage, parseOptionList,
|
||||
(const String *)&parseRuleValueStr[parseRuleValStrCFGOPTDEF_CONFIG_PATH_SP_QT_FS_QT_SP_PROJECT_CONFIG_FILE],
|
||||
(const String *)&parseRuleValueStr[parseRuleValStrCFGOPTDEF_CONFIG_PATH_SP_QT_FS_QT_SP_PROJECT_CONFIG_INCLUDE_PATH],
|
||||
PGBACKREST_CONFIG_ORIG_PATH_FILE_STR);
|
||||
|
||||
if (configString != NULL)
|
||||
{
|
||||
@ -1800,115 +2091,87 @@ configParse(const Storage *storage, unsigned int argListSize, const char *argLis
|
||||
// Initialize option value and set negate and reset flag
|
||||
*configOptionValue = (ConfigOptionValue){.negate = parseOptionValue->negate, .reset = parseOptionValue->reset};
|
||||
|
||||
// Check option dependencies
|
||||
bool dependResolved = true;
|
||||
ParseRuleOptionData depend = parseRuleOptionDataFind(parseRuleOptionDataTypeDepend, config->command, optionId);
|
||||
// Is the option valid?
|
||||
bool valid = true;
|
||||
CfgParseOptionalRuleState optionalRules = {0};
|
||||
|
||||
if (depend.found)
|
||||
if (cfgParseOptionalRule(&optionalRules, parseRuleOptionalTypeValid, config->command, optionId))
|
||||
{
|
||||
ConfigOption dependOptionId = (ConfigOption)depend.data;
|
||||
ConfigOptionType dependOptionType = cfgParseOptionType(dependOptionId);
|
||||
PackRead *filter = pckReadNewC(optionalRules.valid, optionalRules.validSize);
|
||||
valid = cfgParseOptionalFilterDepend(filter, config, optionListIdx);
|
||||
|
||||
ASSERT(config->option[dependOptionId].index != NULL);
|
||||
|
||||
// Get the depend option value
|
||||
const Variant *dependValue = config->option[dependOptionId].index[optionListIdx].value;
|
||||
|
||||
if (dependValue != NULL)
|
||||
// If depend not resolved and option value is set on the command-line then error. It is OK to have
|
||||
// unresolved options in the config file because they may be there for another command. For instance,
|
||||
// spool-path is only loaded for the archive-push command when archive-async=y, and the presence of
|
||||
// spool-path in the config file should not cause an error here, it will just end up null.
|
||||
if (!valid && optionSet && parseOptionValue->source == cfgSourceParam)
|
||||
{
|
||||
if (dependOptionType == cfgOptTypeBoolean)
|
||||
{
|
||||
if (varBool(dependValue))
|
||||
dependValue = OPTION_VALUE_1;
|
||||
else
|
||||
dependValue = OPTION_VALUE_0;
|
||||
}
|
||||
}
|
||||
PackRead *filter = pckReadNewC(optionalRules.valid, optionalRules.validSize);
|
||||
ConfigOption dependId = pckReadU32P(filter);
|
||||
|
||||
// Can't resolve if the depend option value is null
|
||||
if (dependValue == NULL)
|
||||
{
|
||||
dependResolved = false;
|
||||
// Get depend option name
|
||||
const String *dependOptionName = STR(cfgParseOptionKeyIdxName(dependId, optionKeyIdx));
|
||||
|
||||
// If depend not resolved and option value is set on the command-line then error. See unresolved list
|
||||
// depend below for a detailed explanation.
|
||||
if (optionSet && parseOptionValue->source == cfgSourceParam)
|
||||
// If depend value is not set
|
||||
ASSERT(config->option[dependId].index != NULL);
|
||||
|
||||
if (config->option[dependId].index[optionListIdx].value == NULL)
|
||||
{
|
||||
THROW_FMT(
|
||||
OptionInvalidError, "option '%s' not valid without option '%s'",
|
||||
cfgParseOptionKeyIdxName(optionId, optionKeyIdx),
|
||||
cfgParseOptionKeyIdxName(dependOptionId, optionKeyIdx));
|
||||
cfgParseOptionKeyIdxName(optionId, optionKeyIdx), strZ(dependOptionName));
|
||||
}
|
||||
}
|
||||
// If a depend list exists, make sure the value is in the list
|
||||
else if (depend.listSize > 0)
|
||||
{
|
||||
dependResolved = false;
|
||||
|
||||
for (unsigned int listIdx = 0; listIdx < depend.listSize; listIdx++)
|
||||
// Build type dependent error data
|
||||
const String *errorValue = EMPTY_STR;
|
||||
|
||||
switch(cfgParseOptionDataType(dependId))
|
||||
{
|
||||
if (strEqZ(varStr(dependValue), (const char *)depend.list[listIdx]))
|
||||
case cfgOptDataTypeBoolean:
|
||||
{
|
||||
dependResolved = true;
|
||||
if (!pckReadBoolP(filter))
|
||||
dependOptionName = strNewFmt("no-%s", strZ(dependOptionName));
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If depend not resolved and option value is set on the command-line then error. It's OK to have
|
||||
// unresolved options in the config file because they may be there for another command. For instance,
|
||||
// spool-path is only loaded for the archive-push command when archive-async=y, and the presence of
|
||||
// spool-path in the config file should not cause an error here, it will just end up null.
|
||||
if (!dependResolved && optionSet && parseOptionValue->source == cfgSourceParam)
|
||||
{
|
||||
// Get the depend option name
|
||||
const String *dependOptionName = STR(cfgParseOptionKeyIdxName(dependOptionId, optionKeyIdx));
|
||||
|
||||
// Build the list of possible depend values
|
||||
StringList *dependValueList = strLstNew();
|
||||
|
||||
for (unsigned int listIdx = 0; listIdx < depend.listSize; listIdx++)
|
||||
default:
|
||||
{
|
||||
const char *dependValue = (const char *)depend.list[listIdx];
|
||||
ASSERT(cfgParseOptionDataType(dependId) == cfgOptDataTypeString);
|
||||
|
||||
// Build list based on depend option type
|
||||
if (dependOptionType == cfgOptTypeBoolean)
|
||||
String *const errorList = strNew();
|
||||
unsigned int validSize = 0;
|
||||
|
||||
while (pckReadNext(filter))
|
||||
{
|
||||
// Boolean outputs depend option name as no-* when false
|
||||
if (strcmp(dependValue, ZERO_Z) == 0)
|
||||
{
|
||||
dependOptionName =
|
||||
strNewFmt("no-%s", cfgParseOptionKeyIdxName(dependOptionId, optionKeyIdx));
|
||||
}
|
||||
strCatFmt(
|
||||
errorList, "%s'%s'", validSize != 0 ? ", " : "",
|
||||
strZ(strIdToStr(parseRuleValueStrId[pckReadU32P(filter)])));
|
||||
|
||||
validSize++;
|
||||
}
|
||||
|
||||
ASSERT(validSize > 0);
|
||||
|
||||
if (validSize == 1)
|
||||
errorValue = strNewFmt(" = %s", strZ(errorList));
|
||||
else
|
||||
{
|
||||
ASSERT(dependOptionType == cfgOptTypePath || dependOptionType == cfgOptTypeString);
|
||||
strLstAdd(dependValueList, strNewFmt("'%s'", dependValue));
|
||||
}
|
||||
errorValue = strNewFmt(" in (%s)", strZ(errorList));
|
||||
}
|
||||
|
||||
// Build the error string
|
||||
const String *errorValue = EMPTY_STR;
|
||||
|
||||
if (strLstSize(dependValueList) == 1)
|
||||
errorValue = strNewFmt(" = %s", strZ(strLstGet(dependValueList, 0)));
|
||||
else if (strLstSize(dependValueList) > 1)
|
||||
errorValue = strNewFmt(" in (%s)", strZ(strLstJoin(dependValueList, ", ")));
|
||||
|
||||
// Throw the error
|
||||
THROW(
|
||||
OptionInvalidError,
|
||||
strZ(
|
||||
strNewFmt(
|
||||
"option '%s' not valid without option '%s'%s",
|
||||
cfgParseOptionKeyIdxName(optionId, optionKeyIdx), strZ(dependOptionName),
|
||||
strZ(errorValue))));
|
||||
}
|
||||
|
||||
THROW(
|
||||
OptionInvalidError,
|
||||
strZ(
|
||||
strNewFmt(
|
||||
"option '%s' not valid without option '%s'%s", cfgParseOptionKeyIdxName(optionId, optionKeyIdx),
|
||||
strZ(dependOptionName), strZ(errorValue))));
|
||||
}
|
||||
|
||||
pckReadFree(filter);
|
||||
}
|
||||
|
||||
// Is the option resolved?
|
||||
if (dependResolved)
|
||||
if (valid)
|
||||
{
|
||||
// Is the option set?
|
||||
if (optionSet)
|
||||
@ -1961,13 +2224,12 @@ configParse(const Storage *storage, unsigned int argListSize, const char *argLis
|
||||
{
|
||||
String *value = strLstGet(parseOptionValue->valueList, 0);
|
||||
const String *valueAllow = value;
|
||||
int64_t valueInt64 = 0;
|
||||
|
||||
// If a numeric type check that the value is valid
|
||||
if (optionType == cfgOptTypeInteger || optionType == cfgOptTypeSize ||
|
||||
optionType == cfgOptTypeTime)
|
||||
{
|
||||
int64_t valueInt64 = 0;
|
||||
|
||||
// Preserve original value to display
|
||||
MEM_CONTEXT_BEGIN(config->memContext)
|
||||
{
|
||||
@ -2021,13 +2283,9 @@ configParse(const Storage *storage, unsigned int argListSize, const char *argLis
|
||||
}
|
||||
TRY_END();
|
||||
|
||||
// Check value range
|
||||
ParseRuleOptionData allowRange = parseRuleOptionDataFind(
|
||||
parseRuleOptionDataTypeAllowRange, config->command, optionId);
|
||||
|
||||
if (allowRange.found &&
|
||||
(valueInt64 < PARSE_RULE_DATA_INT64(allowRange, 0) ||
|
||||
valueInt64 > PARSE_RULE_DATA_INT64(allowRange, 2)))
|
||||
if (cfgParseOptionalRule(
|
||||
&optionalRules, parseRuleOptionalTypeAllowRange, config->command, optionId) &&
|
||||
(valueInt64 < optionalRules.allowRangeMin || valueInt64 > optionalRules.allowRangeMax))
|
||||
{
|
||||
THROW_FMT(
|
||||
OptionInvalidValueError, "'%s' is out of range for '%s' option", strZ(value),
|
||||
@ -2077,23 +2335,67 @@ configParse(const Storage *storage, unsigned int argListSize, const char *argLis
|
||||
}
|
||||
|
||||
// If the option has an allow list then check it
|
||||
ParseRuleOptionData allowList = parseRuleOptionDataFind(
|
||||
parseRuleOptionDataTypeAllowList, config->command, optionId);
|
||||
|
||||
if (allowList.found)
|
||||
if (cfgParseOptionalRule(
|
||||
&optionalRules, parseRuleOptionalTypeAllowList, config->command, optionId))
|
||||
{
|
||||
unsigned int listIdx = 0;
|
||||
PackRead *const allowList = pckReadNewC(optionalRules.allowList, optionalRules.allowListSize);
|
||||
bool allowListFound = false;
|
||||
|
||||
for (; listIdx < allowList.listSize; listIdx++)
|
||||
if (parseRuleOption[optionId].type == cfgOptTypeString)
|
||||
{
|
||||
if (strEqZ(valueAllow, (const char *)allowList.list[listIdx]))
|
||||
break;
|
||||
bool valueValid = true;
|
||||
StringId value = 0;
|
||||
|
||||
TRY_BEGIN()
|
||||
{
|
||||
TRY_BEGIN()
|
||||
{
|
||||
value = strIdFromStr(stringIdBit5, valueAllow);
|
||||
}
|
||||
CATCH_ANY()
|
||||
{
|
||||
value = strIdFromStr(stringIdBit6, valueAllow);
|
||||
}
|
||||
TRY_END();
|
||||
}
|
||||
CATCH_ANY()
|
||||
{
|
||||
valueValid = false;
|
||||
}
|
||||
TRY_END();
|
||||
|
||||
if (valueValid)
|
||||
{
|
||||
while (pckReadNext(allowList))
|
||||
{
|
||||
if (parseRuleValueStrId[pckReadU32P(allowList)] == value)
|
||||
{
|
||||
allowListFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ASSERT(parseRuleOption[optionId].type == cfgOptTypeSize);
|
||||
|
||||
while (pckReadNext(allowList))
|
||||
{
|
||||
if (parseRuleValueInt[pckReadU32P(allowList)] == valueInt64)
|
||||
{
|
||||
allowListFound = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (listIdx == allowList.listSize)
|
||||
pckReadFree(allowList);
|
||||
|
||||
if (!allowListFound)
|
||||
{
|
||||
THROW_FMT(
|
||||
OptionInvalidValueError, "'%s' is not allowed for '%s' option", strZ(value),
|
||||
OptionInvalidValueError, "'%s' is not allowed for '%s' option", strZ(valueAllow),
|
||||
cfgParseOptionKeyIdxName(optionId, optionKeyIdx));
|
||||
}
|
||||
}
|
||||
@ -2104,46 +2406,41 @@ configParse(const Storage *storage, unsigned int argListSize, const char *argLis
|
||||
// Else try to set a default
|
||||
else
|
||||
{
|
||||
// Get the default value for this option
|
||||
const char *value = cfgParseOptionDefault(config->command, optionId);
|
||||
bool found = false;
|
||||
|
||||
MEM_CONTEXT_BEGIN(config->memContext)
|
||||
{
|
||||
found = cfgParseOptionalRule(
|
||||
&optionalRules, parseRuleOptionalTypeDefault, config->command, optionId);
|
||||
}
|
||||
MEM_CONTEXT_END();
|
||||
|
||||
// If the option has a default
|
||||
if (value != NULL)
|
||||
if (found)
|
||||
{
|
||||
MEM_CONTEXT_BEGIN(config->memContext)
|
||||
{
|
||||
// This would typically be a switch but since not all cases are covered it would require a
|
||||
// separate function which does not seem worth it. The eventual plan is to have all the defaults
|
||||
// represented as constants so they can be assigned directly without creating variants.
|
||||
if (optionType == cfgOptTypeBoolean)
|
||||
configOptionValue->value = strcmp(value, ONE_Z) == 0 ? BOOL_TRUE_VAR : BOOL_FALSE_VAR;
|
||||
else if (optionType == cfgOptTypePath || optionType == cfgOptTypeString)
|
||||
configOptionValue->value = varNewStrZ(value);
|
||||
else
|
||||
{
|
||||
ASSERT(
|
||||
optionType == cfgOptTypeInteger || optionType == cfgOptTypeSize ||
|
||||
optionType == cfgOptTypeTime);
|
||||
|
||||
configOptionValue->value = varNewInt64(cvtZToInt64(value));
|
||||
}
|
||||
}
|
||||
MEM_CONTEXT_END();
|
||||
configOptionValue->value = optionalRules.defaultValue;
|
||||
}
|
||||
// Else error if option is required and help was not requested
|
||||
else if (cfgParseOptionRequired(config->command, optionId) && !config->help)
|
||||
else
|
||||
{
|
||||
const char *hint = "";
|
||||
const bool required = cfgParseOptionalRule(
|
||||
&optionalRules, parseRuleOptionalTypeRequired, config->command, optionId) ?
|
||||
optionalRules.required : parseRuleOption[optionId].required;
|
||||
|
||||
if (parseRuleOption[optionId].section == cfgSectionStanza)
|
||||
hint = "\nHINT: does this stanza exist?";
|
||||
|
||||
THROW_FMT(
|
||||
OptionRequiredError, "%s command requires option: %s%s", cfgParseCommandName(config->command),
|
||||
cfgParseOptionKeyIdxName(optionId, optionKeyIdx), hint);
|
||||
if (required && !config->help)
|
||||
{
|
||||
THROW_FMT(
|
||||
OptionRequiredError, "%s command requires option: %s%s",
|
||||
cfgParseCommandName(config->command),
|
||||
cfgParseOptionKeyIdxName(optionId, optionKeyIdx),
|
||||
parseRuleOption[optionId].section == cfgSectionStanza ?
|
||||
"\nHINT: does this stanza exist?" : "");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pckReadFree(optionalRules.pack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ typedef struct CfgParseOptionResult
|
||||
CfgParseOptionResult cfgParseOption(const String *const optionName, const CfgParseOptionParam param);
|
||||
|
||||
// Default value for the option
|
||||
const char *cfgParseOptionDefault(ConfigCommand commandId, ConfigOption optionId);
|
||||
const String *cfgParseOptionDefault(ConfigCommand commandId, ConfigOption optionId);
|
||||
|
||||
// Option name from id
|
||||
const char *cfgParseOptionName(ConfigOption optionId);
|
||||
|
@ -228,8 +228,28 @@ testRun(void)
|
||||
" timeout:\n"
|
||||
" type: time\n"
|
||||
" default: 10\n"
|
||||
" command:\n"
|
||||
" backup:\n"
|
||||
" default: 20\n"
|
||||
" archive-get:\n"
|
||||
" default: 30\n"
|
||||
" allow-range: [5, 50]\n"
|
||||
"\n"
|
||||
" buffer-size:\n"
|
||||
" section: global\n"
|
||||
" type: size\n"
|
||||
" command:\n"
|
||||
" backup: {}\n"
|
||||
" archive-get:\n"
|
||||
" default: 32768\n"
|
||||
" allow-list:\n"
|
||||
" - 32768\n"
|
||||
" allow-list:\n"
|
||||
" - 8192\n"
|
||||
" - 16384\n"
|
||||
" command-role:\n"
|
||||
" main: {}\n"
|
||||
"\n"
|
||||
" compress-type:\n"
|
||||
" section: global\n"
|
||||
" type: string\n"
|
||||
@ -267,6 +287,17 @@ testRun(void)
|
||||
" default: CFGOPTDEF_CONFIG_PATH \"/\" PROJECT_CONFIG_FILE\n"
|
||||
" default-literal: true\n"
|
||||
" negate: true\n"
|
||||
" command:\n"
|
||||
" backup: {}\n"
|
||||
" archive-get:\n"
|
||||
" default: CFGOPTDEF_CONFIG_PATH \"/.\" PROJECT_CONFIG_FILE\n"
|
||||
"\n"
|
||||
" config-include:\n"
|
||||
" section: global\n"
|
||||
" type: path\n"
|
||||
" default: /include\n"
|
||||
" command-role:\n"
|
||||
" main: {}\n"
|
||||
"\n"
|
||||
" log-level-console:\n"
|
||||
" section: global\n"
|
||||
@ -311,7 +342,8 @@ testRun(void)
|
||||
" type: boolean\n"
|
||||
" default: true\n"
|
||||
" command:\n"
|
||||
" backup: {}\n"
|
||||
" backup:\n"
|
||||
" default: false\n"
|
||||
" command-role:\n"
|
||||
" main: {}\n"
|
||||
" deprecate:\n"
|
||||
@ -323,6 +355,8 @@ testRun(void)
|
||||
" default: false\n"
|
||||
" depend:\n"
|
||||
" option: online\n"
|
||||
" list:\n"
|
||||
" - true\n"
|
||||
" command:\n"
|
||||
" backup: {}\n"
|
||||
" command-role:\n"
|
||||
@ -345,11 +379,20 @@ testRun(void)
|
||||
" section: stanza\n"
|
||||
" group: pg\n"
|
||||
" type: string\n"
|
||||
" command:\n"
|
||||
" archive-get:\n"
|
||||
" default: host1\n"
|
||||
" backup: {}\n"
|
||||
" deprecate:\n"
|
||||
" pg?-host: {}\n");
|
||||
|
||||
TEST_RESULT_VOID(bldCfgRender(storageTest, bldCfgParse(storageTest)), "parse and render");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("bldCfgRenderVar128Size()");
|
||||
|
||||
TEST_RESULT_UINT(bldCfgRenderVar128Size(10000), 2, "check size");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("check config.auto.h");
|
||||
|
||||
@ -383,17 +426,19 @@ testRun(void)
|
||||
"Option constants\n"
|
||||
COMMENT_BLOCK_END "\n"
|
||||
"#define CFGOPT_BACKUP_STANDBY \"backup-standby\"\n"
|
||||
"#define CFGOPT_BUFFER_SIZE \"buffer-size\"\n"
|
||||
"#define CFGOPT_COMPRESS_LEVEL \"compress-level\"\n"
|
||||
"#define CFGOPT_COMPRESS_LEVEL_NETWORK \"compress-level-network\"\n"
|
||||
"#define CFGOPT_COMPRESS_TYPE \"compress-type\"\n"
|
||||
"#define CFGOPT_CONFIG \"config\"\n"
|
||||
"#define CFGOPT_CONFIG_INCLUDE \"config-include\"\n"
|
||||
"#define CFGOPT_LOG_LEVEL_CONSOLE \"log-level-console\"\n"
|
||||
"#define CFGOPT_LOG_LEVEL_FILE \"log-level-file\"\n"
|
||||
"#define CFGOPT_ONLINE \"online\"\n"
|
||||
"#define CFGOPT_STANZA \"stanza\"\n"
|
||||
"#define CFGOPT_TIMEOUT \"timeout\"\n"
|
||||
"\n"
|
||||
"#define CFG_OPTION_TOTAL 12\n"
|
||||
"#define CFG_OPTION_TOTAL 14\n"
|
||||
"\n"
|
||||
COMMENT_BLOCK_BEGIN "\n"
|
||||
"Option value constants\n"
|
||||
@ -443,10 +488,12 @@ testRun(void)
|
||||
"typedef enum\n"
|
||||
"{\n"
|
||||
" cfgOptBackupStandby,\n"
|
||||
" cfgOptBufferSize,\n"
|
||||
" cfgOptCompressLevel,\n"
|
||||
" cfgOptCompressLevelNetwork,\n"
|
||||
" cfgOptCompressType,\n"
|
||||
" cfgOptConfig,\n"
|
||||
" cfgOptConfigInclude,\n"
|
||||
" cfgOptLogLevelConsole,\n"
|
||||
" cfgOptLogLevelFile,\n"
|
||||
" cfgOptOnline,\n"
|
||||
@ -471,8 +518,101 @@ testRun(void)
|
||||
COMMENT_BLOCK_END "\n"
|
||||
"\n"
|
||||
COMMENT_BLOCK_BEGIN "\n"
|
||||
"Rule Strings\n"
|
||||
COMMENT_BLOCK_END "\n"
|
||||
"#define PARSE_RULE_VAL_STR(value) PARSE_RULE_U32_1(value)\n"
|
||||
"\n"
|
||||
"static const StringPub parseRuleValueStr[] =\n"
|
||||
"{\n"
|
||||
" PARSE_RULE_STRPUB(\"/include\"),\n"
|
||||
" PARSE_RULE_STRPUB(\"10\"),\n"
|
||||
" PARSE_RULE_STRPUB(\"20\"),\n"
|
||||
" PARSE_RULE_STRPUB(\"30\"),\n"
|
||||
" PARSE_RULE_STRPUB(\"32768\"),\n"
|
||||
" PARSE_RULE_STRPUB(\"gz\"),\n"
|
||||
" PARSE_RULE_STRPUB(\"host1\"),\n"
|
||||
" PARSE_RULE_STRPUB(\"info\"),\n"
|
||||
" PARSE_RULE_STRPUB(\"warn\"),\n"
|
||||
" PARSE_RULE_STRPUB(CFGOPTDEF_CONFIG_PATH \"/\" PROJECT_CONFIG_FILE),\n"
|
||||
" PARSE_RULE_STRPUB(CFGOPTDEF_CONFIG_PATH \"/.\" PROJECT_CONFIG_FILE),\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"typedef enum\n"
|
||||
"{\n"
|
||||
" parseRuleValStrQT_FS_include_QT,\n"
|
||||
" parseRuleValStrQT_10_QT,\n"
|
||||
" parseRuleValStrQT_20_QT,\n"
|
||||
" parseRuleValStrQT_30_QT,\n"
|
||||
" parseRuleValStrQT_32768_QT,\n"
|
||||
" parseRuleValStrQT_gz_QT,\n"
|
||||
" parseRuleValStrQT_host1_QT,\n"
|
||||
" parseRuleValStrQT_info_QT,\n"
|
||||
" parseRuleValStrQT_warn_QT,\n"
|
||||
" parseRuleValStrCFGOPTDEF_CONFIG_PATH_SP_QT_FS_QT_SP_PROJECT_CONFIG_FILE,\n"
|
||||
" parseRuleValStrCFGOPTDEF_CONFIG_PATH_SP_QT_FS_DT_QT_SP_PROJECT_CONFIG_FILE,\n"
|
||||
"} ParseRuleValueStr;\n"
|
||||
"\n"
|
||||
COMMENT_BLOCK_BEGIN "\n"
|
||||
"Rule StringIds\n"
|
||||
COMMENT_BLOCK_END "\n"
|
||||
"#define PARSE_RULE_VAL_STRID(value) PARSE_RULE_U32_1(value)\n"
|
||||
"\n"
|
||||
"static const StringId parseRuleValueStrId[] =\n"
|
||||
"{\n"
|
||||
" STRID6(\"debug1\", 0x7475421441),\n"
|
||||
" STRID5(\"error\", 0x127ca450),\n"
|
||||
" STRID5(\"info\", 0x799c90),\n"
|
||||
" STRID5(\"off\", 0x18cf0),\n"
|
||||
" STRID5(\"warn\", 0x748370),\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"typedef enum\n"
|
||||
"{\n"
|
||||
" parseRuleValStrIdDebug1,\n"
|
||||
" parseRuleValStrIdError,\n"
|
||||
" parseRuleValStrIdInfo,\n"
|
||||
" parseRuleValStrIdOff,\n"
|
||||
" parseRuleValStrIdWarn,\n"
|
||||
"} ParseRuleValueStrId;\n"
|
||||
"\n"
|
||||
COMMENT_BLOCK_BEGIN "\n"
|
||||
"Rule Ints\n"
|
||||
COMMENT_BLOCK_END "\n"
|
||||
"#define PARSE_RULE_VAL_INT(value) PARSE_RULE_U32_1(value)\n"
|
||||
"\n"
|
||||
"static const int64_t parseRuleValueInt[] =\n"
|
||||
"{\n"
|
||||
" 0,\n"
|
||||
" 9,\n"
|
||||
" 5000,\n"
|
||||
" 8192,\n"
|
||||
" 10000,\n"
|
||||
" 16384,\n"
|
||||
" 20000,\n"
|
||||
" 30000,\n"
|
||||
" 32768,\n"
|
||||
" 50000,\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
"typedef enum\n"
|
||||
"{\n"
|
||||
" parseRuleValInt0,\n"
|
||||
" parseRuleValInt9,\n"
|
||||
" parseRuleValInt5000,\n"
|
||||
" parseRuleValInt8192,\n"
|
||||
" parseRuleValInt10000,\n"
|
||||
" parseRuleValInt16384,\n"
|
||||
" parseRuleValInt20000,\n"
|
||||
" parseRuleValInt30000,\n"
|
||||
" parseRuleValInt32768,\n"
|
||||
" parseRuleValInt50000,\n"
|
||||
"} ParseRuleValueInt;\n"
|
||||
"\n"
|
||||
COMMENT_BLOCK_BEGIN "\n"
|
||||
"Command parse data\n"
|
||||
COMMENT_BLOCK_END "\n"
|
||||
"#define PARSE_RULE_VAL_CMD(value) PARSE_RULE_U32_1(value)\n"
|
||||
"\n"
|
||||
"static const ParseRuleCommand parseRuleCommand[CFG_COMMAND_TOTAL] =\n"
|
||||
"{\n"
|
||||
COMMENT_SEPARATOR "\n"
|
||||
@ -560,6 +700,8 @@ testRun(void)
|
||||
COMMENT_BLOCK_BEGIN "\n"
|
||||
"Option parse data\n"
|
||||
COMMENT_BLOCK_END "\n"
|
||||
"#define PARSE_RULE_VAL_OPT(value) PARSE_RULE_U32_1(value)\n"
|
||||
"\n"
|
||||
"static const ParseRuleOption parseRuleOption[CFG_OPTION_TOTAL] =\n"
|
||||
"{\n"
|
||||
COMMENT_SEPARATOR "\n"
|
||||
@ -577,10 +719,68 @@ testRun(void)
|
||||
" PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_LIST\n"
|
||||
" PARSE_RULE_OPTIONAL\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_DEPEND(cfgOptOnline),\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_DEFAULT(\"0\"),\n"
|
||||
" PARSE_RULE_OPTIONAL_GROUP\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTIONAL_DEPEND\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_OPT(cfgOptOnline),\n"
|
||||
" PARSE_RULE_VAL_BOOL_TRUE,\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL_DEFAULT\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_BOOL_FALSE,\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
COMMENT_SEPARATOR "\n"
|
||||
" PARSE_RULE_OPTION\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTION_NAME(\"buffer-size\"),\n"
|
||||
" PARSE_RULE_OPTION_TYPE(cfgOptTypeSize),\n"
|
||||
" PARSE_RULE_OPTION_RESET(true),\n"
|
||||
" PARSE_RULE_OPTION_REQUIRED(true),\n"
|
||||
" PARSE_RULE_OPTION_SECTION(cfgSectionGlobal),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTION_COMMAND_ROLE_MAIN_VALID_LIST\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n"
|
||||
" PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTIONAL_GROUP\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_FILTER_CMD\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_CMD(cfgCmdArchiveGet),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL_ALLOW_LIST\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_INT(parseRuleValInt32768),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL_DEFAULT\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_INT(parseRuleValInt32768),\n"
|
||||
" PARSE_RULE_VAL_STR(parseRuleValStrQT_32768_QT),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL_GROUP\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTIONAL_ALLOW_LIST\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_INT(parseRuleValInt8192),\n"
|
||||
" PARSE_RULE_VAL_INT(parseRuleValInt16384),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
@ -616,16 +816,35 @@ testRun(void)
|
||||
" PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_LIST\n"
|
||||
" PARSE_RULE_OPTIONAL\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_ALLOW_RANGE(0, 9),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_COMMAND_OVERRIDE\n"
|
||||
" PARSE_RULE_OPTIONAL_GROUP\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_COMMAND(cfgCmdArchiveGet),\n"
|
||||
" PARSE_RULE_FILTER_CMD\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_CMD(cfgCmdArchiveGet),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_DEPEND(cfgOptConfig),\n"
|
||||
" )\n"
|
||||
" PARSE_RULE_OPTIONAL_DEPEND\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_OPT(cfgOptConfig),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL_ALLOW_RANGE\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_INT(parseRuleValInt0),\n"
|
||||
" PARSE_RULE_VAL_INT(parseRuleValInt9),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL_GROUP\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTIONAL_ALLOW_RANGE\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_INT(parseRuleValInt0),\n"
|
||||
" PARSE_RULE_VAL_INT(parseRuleValInt9),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
@ -662,22 +881,42 @@ testRun(void)
|
||||
" PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_LIST\n"
|
||||
" PARSE_RULE_OPTIONAL\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_ALLOW_RANGE(0, 9),\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_DEPEND_LIST\n"
|
||||
" PARSE_RULE_OPTIONAL_GROUP\n"
|
||||
" (\n"
|
||||
" cfgOptCompressType,\n"
|
||||
" \"none\",\n"
|
||||
" \"gz\"\n"
|
||||
" PARSE_RULE_FILTER_CMD\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_CMD(cfgCmdArchiveGet),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL_DEPEND\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_OPT(cfgOptConfig),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL_ALLOW_RANGE\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_INT(parseRuleValInt0),\n"
|
||||
" PARSE_RULE_VAL_INT(parseRuleValInt9),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_COMMAND_OVERRIDE\n"
|
||||
" PARSE_RULE_OPTIONAL_GROUP\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_COMMAND(cfgCmdArchiveGet),\n"
|
||||
" PARSE_RULE_OPTIONAL_DEPEND\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_OPT(cfgOptCompressType),\n"
|
||||
" PARSE_RULE_VAL_STRID(parseRuleValStrIdNone),\n"
|
||||
" PARSE_RULE_VAL_STRID(parseRuleValStrIdGz),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_DEPEND(cfgOptConfig),\n"
|
||||
" )\n"
|
||||
" PARSE_RULE_OPTIONAL_ALLOW_RANGE\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_INT(parseRuleValInt0),\n"
|
||||
" PARSE_RULE_VAL_INT(parseRuleValInt9),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
@ -690,16 +929,33 @@ testRun(void)
|
||||
" PARSE_RULE_OPTION_REQUIRED(true),\n"
|
||||
" PARSE_RULE_OPTION_SECTION(cfgSectionGlobal),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_LIST\n"
|
||||
" PARSE_RULE_OPTIONAL\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_DEFAULT(\"gz\"),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_COMMAND_OVERRIDE\n"
|
||||
" PARSE_RULE_OPTIONAL_GROUP\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_COMMAND(cfgCmdArchiveGet),\n"
|
||||
" PARSE_RULE_FILTER_CMD\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_CMD(cfgCmdArchiveGet),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_DEPEND(cfgOptConfig),\n"
|
||||
" )\n"
|
||||
" PARSE_RULE_OPTIONAL_DEPEND\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_OPT(cfgOptConfig),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL_DEFAULT\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_STR(parseRuleValStrQT_gz_QT),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL_GROUP\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTIONAL_DEFAULT\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_STR(parseRuleValStrQT_gz_QT),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
@ -735,9 +991,55 @@ testRun(void)
|
||||
" PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_LIST\n"
|
||||
" PARSE_RULE_OPTIONAL\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_DEFAULT(CFGOPTDEF_CONFIG_PATH \"/\" PROJECT_CONFIG_FILE),\n"
|
||||
" PARSE_RULE_OPTIONAL_GROUP\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_FILTER_CMD\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_CMD(cfgCmdArchiveGet),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL_DEFAULT\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_STR(parseRuleValStrCFGOPTDEF_CONFIG_PATH_SP_QT_FS_DT_QT_SP_PROJECT_CONFIG_FILE),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL_GROUP\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTIONAL_DEFAULT\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_STR(parseRuleValStrCFGOPTDEF_CONFIG_PATH_SP_QT_FS_QT_SP_PROJECT_CONFIG_FILE),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
COMMENT_SEPARATOR "\n"
|
||||
" PARSE_RULE_OPTION\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTION_NAME(\"config-include\"),\n"
|
||||
" PARSE_RULE_OPTION_TYPE(cfgOptTypePath),\n"
|
||||
" PARSE_RULE_OPTION_RESET(true),\n"
|
||||
" PARSE_RULE_OPTION_REQUIRED(true),\n"
|
||||
" PARSE_RULE_OPTION_SECTION(cfgSectionGlobal),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTION_COMMAND_ROLE_MAIN_VALID_LIST\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n"
|
||||
" PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTIONAL_GROUP\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTIONAL_DEFAULT\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_STR(parseRuleValStrQT_FS_include_QT),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
@ -773,17 +1075,23 @@ testRun(void)
|
||||
" PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_LIST\n"
|
||||
" PARSE_RULE_OPTIONAL\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_ALLOW_LIST\n"
|
||||
" PARSE_RULE_OPTIONAL_GROUP\n"
|
||||
" (\n"
|
||||
" \"off\",\n"
|
||||
" \"error\",\n"
|
||||
" \"warn\",\n"
|
||||
" \"debug1\"\n"
|
||||
" ),\n"
|
||||
" PARSE_RULE_OPTIONAL_ALLOW_LIST\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_STRID(parseRuleValStrIdOff),\n"
|
||||
" PARSE_RULE_VAL_STRID(parseRuleValStrIdError),\n"
|
||||
" PARSE_RULE_VAL_STRID(parseRuleValStrIdWarn),\n"
|
||||
" PARSE_RULE_VAL_STRID(parseRuleValStrIdDebug1),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_DEFAULT(\"warn\"),\n"
|
||||
" PARSE_RULE_OPTIONAL_DEFAULT\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_STR(parseRuleValStrQT_warn_QT),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
@ -818,37 +1126,50 @@ testRun(void)
|
||||
" PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_LIST\n"
|
||||
" PARSE_RULE_OPTIONAL\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_ALLOW_LIST\n"
|
||||
" PARSE_RULE_OPTIONAL_GROUP\n"
|
||||
" (\n"
|
||||
" \"off\",\n"
|
||||
" \"error\",\n"
|
||||
" \"warn\",\n"
|
||||
" \"debug1\"\n"
|
||||
" PARSE_RULE_FILTER_CMD\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_CMD(cfgCmdBackup),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL_DEPEND\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_OPT(cfgOptLogLevelConsole),\n"
|
||||
" PARSE_RULE_VAL_STRID(parseRuleValStrIdWarn),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL_ALLOW_LIST\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_STRID(parseRuleValStrIdOff),\n"
|
||||
" PARSE_RULE_VAL_STRID(parseRuleValStrIdWarn),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL_DEFAULT\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_STR(parseRuleValStrQT_warn_QT),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL_NOT_REQUIRED(),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_DEFAULT(\"info\"),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_COMMAND_OVERRIDE\n"
|
||||
" PARSE_RULE_OPTIONAL_GROUP\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_COMMAND(cfgCmdBackup),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_ALLOW_LIST\n"
|
||||
" PARSE_RULE_OPTIONAL_ALLOW_LIST\n"
|
||||
" (\n"
|
||||
" \"off\",\n"
|
||||
" \"warn\"\n"
|
||||
" PARSE_RULE_VAL_STRID(parseRuleValStrIdOff),\n"
|
||||
" PARSE_RULE_VAL_STRID(parseRuleValStrIdError),\n"
|
||||
" PARSE_RULE_VAL_STRID(parseRuleValStrIdWarn),\n"
|
||||
" PARSE_RULE_VAL_STRID(parseRuleValStrIdDebug1),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_DEPEND_LIST\n"
|
||||
" PARSE_RULE_OPTIONAL_DEFAULT\n"
|
||||
" (\n"
|
||||
" cfgOptLogLevelConsole,\n"
|
||||
" \"warn\"\n"
|
||||
" PARSE_RULE_VAL_STR(parseRuleValStrQT_info_QT),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_DEFAULT(\"warn\"),\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_REQUIRED(false),\n"
|
||||
" )\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
@ -865,9 +1186,28 @@ testRun(void)
|
||||
" PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_LIST\n"
|
||||
" PARSE_RULE_OPTIONAL\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_DEFAULT(\"1\"),\n"
|
||||
" PARSE_RULE_OPTIONAL_GROUP\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_FILTER_CMD\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_CMD(cfgCmdBackup),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL_DEFAULT\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_BOOL_FALSE,\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL_GROUP\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTIONAL_DEFAULT\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_BOOL_TRUE,\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
@ -904,6 +1244,22 @@ testRun(void)
|
||||
" PARSE_RULE_OPTION_COMMAND(cfgCmdArchiveGet)\n"
|
||||
" PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTIONAL_GROUP\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_FILTER_CMD\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_CMD(cfgCmdArchiveGet),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL_DEFAULT\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_STR(parseRuleValStrQT_host1_QT),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
COMMENT_SEPARATOR "\n"
|
||||
@ -1007,10 +1363,62 @@ testRun(void)
|
||||
" PARSE_RULE_OPTION_COMMAND(cfgCmdBackup)\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_LIST\n"
|
||||
" PARSE_RULE_OPTIONAL\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_ALLOW_RANGE(5000, 50000),\n"
|
||||
" PARSE_RULE_OPTION_OPTIONAL_DEFAULT(\"10000\"),\n"
|
||||
" PARSE_RULE_OPTIONAL_GROUP\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_FILTER_CMD\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_CMD(cfgCmdArchiveGet),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL_ALLOW_RANGE\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_INT(parseRuleValInt5000),\n"
|
||||
" PARSE_RULE_VAL_INT(parseRuleValInt50000),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL_DEFAULT\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_INT(parseRuleValInt30000),\n"
|
||||
" PARSE_RULE_VAL_STR(parseRuleValStrQT_30_QT),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL_GROUP\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_FILTER_CMD\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_CMD(cfgCmdBackup),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL_ALLOW_RANGE\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_INT(parseRuleValInt5000),\n"
|
||||
" PARSE_RULE_VAL_INT(parseRuleValInt50000),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL_DEFAULT\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_INT(parseRuleValInt20000),\n"
|
||||
" PARSE_RULE_VAL_STR(parseRuleValStrQT_20_QT),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL_GROUP\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_OPTIONAL_ALLOW_RANGE\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_INT(parseRuleValInt5000),\n"
|
||||
" PARSE_RULE_VAL_INT(parseRuleValInt50000),\n"
|
||||
" ),\n"
|
||||
"\n"
|
||||
" PARSE_RULE_OPTIONAL_DEFAULT\n"
|
||||
" (\n"
|
||||
" PARSE_RULE_VAL_INT(parseRuleValInt10000),\n"
|
||||
" PARSE_RULE_VAL_STR(parseRuleValStrQT_10_QT),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
" ),\n"
|
||||
"};\n"
|
||||
@ -1079,7 +1487,9 @@ testRun(void)
|
||||
"static const ConfigOption optionResolveOrder[] =\n"
|
||||
"{\n"
|
||||
" cfgOptStanza,\n"
|
||||
" cfgOptBufferSize,\n"
|
||||
" cfgOptConfig,\n"
|
||||
" cfgOptConfigInclude,\n"
|
||||
" cfgOptLogLevelConsole,\n"
|
||||
" cfgOptLogLevelFile,\n"
|
||||
" cfgOptOnline,\n"
|
||||
|
@ -127,6 +127,7 @@ testRun(void)
|
||||
TEST_RESULT_STR_Z(helpRenderValue(varNewStrZ("test-string"), cfgOptTypeString), "test-string", "string");
|
||||
TEST_RESULT_STR_Z(helpRenderValue(varNewInt64(1234), cfgOptTypeInteger), "1234", "int");
|
||||
TEST_RESULT_STR_Z(helpRenderValue(varNewInt64(1234000), cfgOptTypeTime), "1234", "time");
|
||||
TEST_RESULT_STR_Z(helpRenderValue(NULL, cfgOptTypeString), NULL, "null");
|
||||
}
|
||||
|
||||
// *****************************************************************************************************************************
|
||||
|
@ -50,6 +50,37 @@ testRun(void)
|
||||
|
||||
TEST_RESULT_UINT(sizeof(ParseRuleOption), TEST_64BIT() ? 40 : 28, "ParseRuleOption size");
|
||||
TEST_RESULT_UINT(sizeof(ParseRuleOptionDeprecate), TEST_64BIT() ? 16 : 12, "ParseRuleOptionDeprecate size");
|
||||
|
||||
// Each pack must be <= 127 bytes because only one byte is used for the size. If this check fails then the size of
|
||||
// PARSE_RULE_PACK_SIZE must be increased. There would be little cost of increasing this as a preventative measure but a
|
||||
// check would still be required, so may as well be as efficient as possible.
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("check that no packs are > 127 bytes");
|
||||
|
||||
unsigned int packOver127 = 0;
|
||||
unsigned int packTotal = 0;
|
||||
size_t packMaxSize = 0;
|
||||
const char *packMaxName = NULL;
|
||||
size_t packTotalSize = 0;
|
||||
|
||||
for (unsigned int optIdx = 0; optIdx < CFG_OPTION_TOTAL; optIdx++)
|
||||
{
|
||||
packOver127 += parseRuleOption[optIdx].packSize > 127;
|
||||
packTotal += parseRuleOption[optIdx].pack != NULL;
|
||||
packTotalSize += parseRuleOption[optIdx].packSize;
|
||||
|
||||
if (parseRuleOption[optIdx].packSize > packMaxSize)
|
||||
{
|
||||
packMaxName = parseRuleOption[optIdx].name;
|
||||
packMaxSize = parseRuleOption[optIdx].packSize;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_RESULT_UINT(packOver127, 0, "no packs over 127 bytes");
|
||||
TEST_LOG_FMT("total size of option packs is %zu bytes", packTotalSize);
|
||||
TEST_LOG_FMT("avg option pack size is %0.2f bytes", (float)packTotalSize / (float)packTotal);
|
||||
TEST_LOG_FMT("max option pack size is '%s' at %zu bytes", packMaxName, packMaxSize);
|
||||
TEST_LOG_FMT("total options with packs is %u (out of %d options) ", packTotal, CFG_OPTION_TOTAL);
|
||||
}
|
||||
|
||||
// Config functions that are not tested with parse
|
||||
@ -161,9 +192,10 @@ testRun(void)
|
||||
HRN_SYSTEM_FMT("mv %s/global-backup.conf %s/global-backup.confsave", strZ(configIncludePath), strZ(configIncludePath));
|
||||
|
||||
// Set up defaults
|
||||
String *backupCmdDefConfigValue = strNewZ(cfgParseOptionDefault(cfgParseCommandId(TEST_COMMAND_BACKUP), cfgOptConfig));
|
||||
String *backupCmdDefConfigInclPathValue = strNewZ(
|
||||
cfgParseOptionDefault(cfgParseCommandId(TEST_COMMAND_BACKUP), cfgOptConfigIncludePath));
|
||||
const String *const backupCmdDefConfigValue =
|
||||
(const String *)&parseRuleValueStr[parseRuleValStrCFGOPTDEF_CONFIG_PATH_SP_QT_FS_QT_SP_PROJECT_CONFIG_FILE];
|
||||
const String *const backupCmdDefConfigInclPathValue =
|
||||
(const String *)&parseRuleValueStr[parseRuleValStrCFGOPTDEF_CONFIG_PATH_SP_QT_FS_QT_SP_PROJECT_CONFIG_INCLUDE_PATH];
|
||||
const String *oldConfigDefault = STRDEF(TEST_PATH PGBACKREST_CONFIG_ORIG_PATH_FILE);
|
||||
|
||||
// Create the option structure and initialize with 0
|
||||
@ -1133,6 +1165,32 @@ testRun(void)
|
||||
configParse(storageTest, strLstSize(argList), strLstPtr(argList), false), OptionInvalidError,
|
||||
"option 'recovery-option' not valid for command 'backup'");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("option value invalid (string)");
|
||||
|
||||
argList = strLstNew();
|
||||
strLstAddZ(argList, TEST_BACKREST_EXE);
|
||||
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/db");
|
||||
hrnCfgArgRawZ(argList, cfgOptStanza, "db");
|
||||
hrnCfgArgRawZ(argList, cfgOptType, "^bogus");
|
||||
strLstAddZ(argList, TEST_COMMAND_RESTORE);
|
||||
TEST_ERROR(
|
||||
configParse(storageTest, strLstSize(argList), strLstPtr(argList), false), OptionInvalidValueError,
|
||||
"'^bogus' is not allowed for 'type' option");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("option value invalid (size)");
|
||||
|
||||
argList = strLstNew();
|
||||
strLstAddZ(argList, TEST_BACKREST_EXE);
|
||||
hrnCfgArgRawZ(argList, cfgOptPgPath, "/path/to/db");
|
||||
hrnCfgArgRawZ(argList, cfgOptStanza, "db");
|
||||
hrnCfgArgRawZ(argList, cfgOptBufferSize, "777");
|
||||
strLstAddZ(argList, TEST_COMMAND_RESTORE);
|
||||
TEST_ERROR(
|
||||
configParse(storageTest, strLstSize(argList), strLstPtr(argList), false), OptionInvalidValueError,
|
||||
"'777' is not allowed for 'buffer-size' option");
|
||||
|
||||
// -------------------------------------------------------------------------------------------------------------------------
|
||||
TEST_TITLE("option value not in allowed list");
|
||||
|
||||
@ -1618,21 +1676,24 @@ testRun(void)
|
||||
TEST_RESULT_STR(cfgOptionIdxStrNull(cfgOptPgHost, 1), NULL, "pg2-host is NULL");
|
||||
TEST_RESULT_STR(cfgOptionStrNull(cfgOptPgHost), NULL, "pg2-host is NULL");
|
||||
TEST_ERROR(cfgOptionIdxStr(cfgOptPgHost, 1), AssertError, "option 'pg2-host' is null but non-null was requested");
|
||||
TEST_RESULT_UINT(cfgOptionUInt64(cfgOptIoTimeout), 60000, "io-timeout is set");
|
||||
|
||||
TEST_RESULT_BOOL(varBool(cfgOptionDefault(cfgOptBackupStandby)), false, "backup-standby default is false");
|
||||
TEST_RESULT_BOOL(varBool(cfgOptionDefault(cfgOptBackupStandby)), false, "backup-standby default is false (again)");
|
||||
TEST_RESULT_BOOL(cfgParseOptionRequired(cfgCmdBackup, cfgOptPgHost), false, "pg-host is not required for backup");
|
||||
TEST_RESULT_BOOL(cfgParseOptionRequired(cfgCmdInfo, cfgOptStanza), false, "stanza is not required for info");
|
||||
|
||||
TEST_RESULT_STR_Z(cfgOptionDefault(cfgOptBackupStandby), "n", "backup-standby default is false");
|
||||
TEST_RESULT_STR_Z(cfgOptionDefault(cfgOptBackupStandby), "n", "backup-standby default is false (again)");
|
||||
TEST_RESULT_PTR(cfgOptionDefault(cfgOptPgHost), NULL, "pg-host default is NULL");
|
||||
TEST_RESULT_STR_Z(varStr(cfgOptionDefault(cfgOptLogLevelConsole)), "warn", "log-level-console default is warn");
|
||||
TEST_RESULT_INT(varInt64(cfgOptionDefault(cfgOptPgPort)), 5432, "pg-port default is 5432");
|
||||
TEST_RESULT_STR_Z(cfgOptionDefault(cfgOptLogLevelConsole), "warn", "log-level-console default is warn");
|
||||
TEST_RESULT_STR_Z(cfgOptionDefault(cfgOptPgPort), "5432", "pg-port default is 5432");
|
||||
TEST_RESULT_STR_Z(cfgOptionDisplay(cfgOptPgPort), "5432", "pg-port display is 5432");
|
||||
TEST_RESULT_INT(varInt64(cfgOptionDefault(cfgOptDbTimeout)), 1800000, "db-timeout default is 1800000");
|
||||
TEST_RESULT_STR_Z(cfgOptionDefault(cfgOptDbTimeout), "1800", "db-timeout default is 1800");
|
||||
|
||||
TEST_RESULT_VOID(cfgOptionDefaultSet(cfgOptPgSocketPath, VARSTRDEF("/default")), "set pg-socket-path default");
|
||||
TEST_RESULT_STR_Z(cfgOptionIdxStr(cfgOptPgSocketPath, 0), "/path/to/socket", "pg1-socket-path unchanged");
|
||||
TEST_RESULT_STR_Z(cfgOptionIdxStr(cfgOptPgSocketPath, 1), "/default", "pg2-socket-path is new default");
|
||||
TEST_RESULT_STR_Z(cfgOptionIdxDisplay(cfgOptPgSocketPath, 1), "/default", "pg2-socket-path display");
|
||||
|
||||
TEST_ERROR(cfgOptionDefaultValue(cfgOptDbInclude), AssertError, "default value not available for option type 3");
|
||||
TEST_ERROR(cfgOptionDisplay(cfgOptTarget), AssertError, "option 'target' is not valid for the current command");
|
||||
TEST_ERROR(cfgOptionLst(cfgOptDbInclude), AssertError, "option 'db-include' is not valid for the current command");
|
||||
TEST_ERROR(cfgOptionKv(cfgOptPgPath), AssertError, "option 'pg1-path' is type 4 but 3 was requested");
|
||||
|
Loading…
x
Reference in New Issue
Block a user